#define FAKE_TREE_IS_VISIBLE 1
/* fake that the tree is visible so that proto.c will not try to
 "fake" generation of finfo values/nodes.
  Thus this means netware dissector is slower than it has to, but it wont crash.
  once the dissector is refactored to avoid calling fvalue_ functions directly this faking of whether the tree is visible or not can be removed.
*/


/* packet-ncp2222.inc
 *
 * Routines for NetWare Core Protocol. This C code gets #include'd
 * into packet-ncp2222.c, which is generated from ncp2222.py. It's
 * #include'd instead of being in a separate compilation unit so
 * that all the data tables in packet-ncp2222.c can remain static.
 *
 * Gilbert Ramirez <gram@alumni.rice.edu>
 * Modified to decode NDS packets by Greg Morris <gmorris@novell.com>
 *
 * Portions Copyright (c) Gilbert Ramirez 2000-2002
 * Portions Copyright (c) Novell, Inc. 2000-2003
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 2000 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

bool nds_defragment  = true;
bool nds_echo_eid    = true;
bool ncp_echo_err    = true;
bool ncp_echo_conn;
bool ncp_echo_server = true;
bool ncp_echo_file;
bool ncp_newstyle    = true;

extern dissector_handle_t nds_data_handle;
typedef struct {
    uint32_t    nds_frag_verb;
    uint32_t    nds_frag_version;
    uint32_t    nds_frag_flags;
    uint32_t    nds_frag_prot_flags;
    uint32_t    nds_length;
    uint32_t    nds_frag;
    bool        nds_fragmented;
    uint8_t     sequence;
} frag_info;

static frag_info           frags[100];
static char    mv_resolve_name_string[128];

static const fragment_items nds_frag_items = {
    &ett_nds_segment,
    &ett_nds_segments,
    &hf_nds_segments,
    &hf_nds_segment,
    &hf_nds_segment_overlap,
    &hf_nds_segment_overlap_conflict,
    &hf_nds_segment_multiple_tails,
    &hf_nds_segment_too_long_segment,
    &hf_nds_segment_error,
    &hf_nds_segment_count,
    NULL,
    &hf_nds_reassembled_length,
    /* Reassembled data field */
    NULL,
    "segments"
};

/* Table for reassembly of fragments. */
static reassembly_table nds_reassembly_table;

#define NDS_TAG_NO_SUCH_ENTRY           0x00000000
#define NDS_TAG_LOCAL_ENTRY             0x00000001
#define NDS_TAG_REMOTE_ENTRY            0x00000002
#define NDS_TAG_ALIAS_ENTRY             0x00000003
#define NDS_TAG_REFERRAL_INFORMATION    0x00000004
#define NDS_TAG_ENTRY_AND_REFERRALS     0x00000006

/* Search objects */
#define NDS_SEARCH_ENTRY                         0
#define NDS_SEARCH_SUBORDINATES                  1
#define NDS_SEARCH_SUBTREE                       2
#define NDS_SEARCH_PARTITION                     3

/* Search Referral Types */
#define NDS_ALIAS_REFERRAL                       0
#define NDS_PARTITION_REFERRAL                   1

/* Search Filter Types */
#define NDS_SEARCH_ITEM                          0
#define NDS_SEARCH_OR                            1
#define NDS_SEARCH_AND                           2
#define NDS_SEARCH_NOT                           3

/* Search Operators */
#define NDS_SEARCH_EQUAL                         7
#define NDS_SEARCH_GREATER_OR_EQUAL              8
#define NDS_SEARCH_LESS_OR_EQUAL                 9
#define NDS_SEARCH_APPROX                       10
#define NDS_SEARCH_PRESENT                      15
#define NDS_SEARCH_RDN                          16
#define NDS_SEARCH_BASE_CLASS                   17
#define NDS_SEARCH_MODIFICATION_GE              18  /* Deprecated, use DS_SEARCH_ENTRY_MTS_GE */
#define NDS_SEARCH_VALUE_TIME_GE                19  /* Deprecated, use DS_SEARCH_VALUE_MTS_GE */
#define NDS_SEARCH_REFERENCES                   20
#define NDS_SEARCH_DN_IN_VALUE                  21
#define NDS_SEARCH_SCHEMA_IN_VALUE              22
#define NDS_SEARCH_ENTRY_FLAGS                  23
#define NDS_SEARCH_ENTRY_HAS_FLAG               24
#define NDS_SEARCH_VALUE_FLAGS                  25
#define NDS_SEARCH_VALUE_HAS_FLAG               26
#define NDS_SEARCH_ATTR_FLAGS                   27
#define NDS_SEARCH_ATTR_HAS_FLAG                28
#define NDS_SEARCH_EID                          29

#define NDS_SEARCH_ENTRY_MTS_GE                 18
#define NDS_SEARCH_ENTRY_MTS_G                  30
#define NDS_SEARCH_ENTRY_MTS_LE                 31
#define NDS_SEARCH_ENTRY_MTS_L                  32
#define NDS_SEARCH_ENTRY_MTS_EQ                 33
#define NDS_SEARCH_ENTRY_MTS_EQ_APPROX          34
#define NDS_SEARCH_VALUE_MTS_GE                 19
#define NDS_SEARCH_VALUE_MTS_G                  35
#define NDS_SEARCH_VALUE_MTS_LE                 36
#define NDS_SEARCH_VALUE_MTS_L                  37
#define NDS_SEARCH_VALUE_MTS_EQ                 38
#define NDS_SEARCH_VALUE_MTS_EQ_APPROX          39

#define NDS_SEARCH_ENTRY_CTS_GE                 40
#define NDS_SEARCH_ENTRY_CTS_G                  41
#define NDS_SEARCH_ENTRY_CTS_LE                 42
#define NDS_SEARCH_ENTRY_CTS_L                  43
#define NDS_SEARCH_ENTRY_CTS_EQ                 44
#define NDS_SEARCH_ENTRY_CTS_EQ_APPROX          45
#define NDS_SEARCH_VALUE_CTS_GE                 46
#define NDS_SEARCH_VALUE_CTS_G                  47
#define NDS_SEARCH_VALUE_CTS_LE                 48
#define NDS_SEARCH_VALUE_CTS_L                  49
#define NDS_SEARCH_VALUE_CTS_EQ                 50
#define NDS_SEARCH_VALUE_CTS_EQ_APPROX          51
#define NDS_SEARCH_EXTENSIBLE                   52
#define NDS_SEARCH_ENTRY_SUBCOUNT_GE            53
#define NDS_SEARCH_ENTRY_SUBCOUNT_G             54
#define NDS_SEARCH_ENTRY_SUBCOUNT_LE            55
#define NDS_SEARCH_ENTRY_SUBCOUNT_L             56
#define NDS_SEARCH_ENTRY_SUBCOUNT_EQ            57

#define DCS_OPS                         0x10000000L
#define DCS_MOD_GE_WITH_ATTR            DCS_OPS + NDS_SEARCH_MODIFICATION_GE
#define DCS_VALUE_GE_WITH_ATTR          DCS_OPS + NDS_SEARCH_VALUE_TIME_GE
#define DCS_MASK                        ~DCS_OPS

/* Iterator verbs */
#define IT_CLEAR                                 1
#define IT_COPY                                  2
#define IT_COUNT                                 3
#define IT_CREATE                                4
#define IT_CURRENT                               5
#define IT_DESTROY                               6
#define IT_DONE                                  7
#define IT_FIRST                                 8
#define IT_GETPOSITION                           9
#define IT_LAST                                 10
#define IT_NEXT                                 11
#define IT_PREV                                 12
#define IT_POSITION                             13
#define IT_POSITION_IT                          14
#define IT_SETINDEX                             15
#define IT_SETFILTER                            16
#define IT_SKIP                                 17
#define IT_TYPEDOWN                             18
#define IT_ATFIRST                              19
#define IT_ATEOF                                20
#define IT_GETINDEX                             21
#define IT_ISPOSITIONABLE                       22
#define IT_ATBOF                                23
#define IT_ATLAST                               24

/* Iteration information flags */
#define DSI_OUTPUT_FIELDS               0x00000001U
#define DSI_ENTRY_ID                    0x00000002U
#define DSI_ENTRY_FLAGS                 0x00000004U
#define DSI_SUBORDINATE_COUNT           0x00000008U
#define DSI_MODIFICATION_TIME           0x00000010U
#define DSI_MODIFICATION_TIMESTAMP      0x00000020U
#define DSI_CREATION_TIMESTAMP          0x00000040U
#define DSI_PARTITION_ROOT_ID           0x00000080U
#define DSI_PARENT_ID                   0x00000100U
#define DSI_REVISION_COUNT              0x00000200U
#define DSI_REPLICA_TYPE                0x00000400U
#define DSI_BASE_CLASS                  0x00000800U
#define DSI_ENTRY_RDN                   0x00001000U
#define DSI_ENTRY_DN                    0x00002000U
#define DSI_PARTITION_ROOT_DN           0x00004000U
#define DSI_PARENT_DN                   0x00008000U
#define DSI_PURGE_TIME                  0x00010000U
#define DSI_DEREFERENCED_BASE_CLASS     0x00020000U
#define DSI_REPLICA_NUMBER              0x00040000U
#define DSI_REPLICA_STATE               0x00080000U
#define DSI_FEDERATION_BOUNDARY         0x00100000U
#define DSI_SCHEMA_BOUNDARY             0x00200000U
#define DSI_FEDERATION_BOUNDARY_ID      0x00400000U
#define DSI_SCHEMA_BOUNDARY_ID          0x00800000U
#define DSI_CUR_SUBCOUNT                0x01000000U
#define DSI_LOCAL_ENTRY_FLAGS           0x02000000U

static const value_string zensearchenum[] = {
    { 0, "[Root]" },
    { 1, "Object Container" },
    { 2, "Associated Container" },
    { 3, "Selected Container" },
    {0, NULL }
};

static const value_string itersearchenum[] = {
    { NDS_SEARCH_ITEM, "Search Item" },
    { NDS_SEARCH_OR, "OR" },
    { NDS_SEARCH_AND, "AND" },
    { NDS_SEARCH_NOT, "NOT" },
    { NDS_SEARCH_EQUAL, "Equals" },
    { NDS_SEARCH_GREATER_OR_EQUAL, "Greater or Equals" },
    { NDS_SEARCH_LESS_OR_EQUAL, "Less or Equals" },
    { NDS_SEARCH_APPROX, "Approximately" },
    { NDS_SEARCH_PRESENT, "Present" },
    { NDS_SEARCH_RDN, "Relative Distinguished Name" },
    { NDS_SEARCH_BASE_CLASS, "Base Class" },
    { NDS_SEARCH_MODIFICATION_GE, "Modification Greater or Equal" },
    { NDS_SEARCH_VALUE_TIME_GE, "Time Value Greater or Equal" },
    { NDS_SEARCH_REFERENCES, "References" },
    { NDS_SEARCH_DN_IN_VALUE, "Designated Name in Value" },
    { NDS_SEARCH_SCHEMA_IN_VALUE, "Schema in Value" },
    { NDS_SEARCH_ENTRY_FLAGS, "Entry Flags" },
    { NDS_SEARCH_ENTRY_HAS_FLAG, "Entry has Flags" },
    { NDS_SEARCH_VALUE_FLAGS, "Value Flags" },
    { NDS_SEARCH_VALUE_HAS_FLAG, "Value has Flags" },
    { NDS_SEARCH_ATTR_FLAGS, "Attribute Flags" },
    { NDS_SEARCH_ATTR_HAS_FLAG, "Attribute has Flags" },
    { NDS_SEARCH_EID, "Entry ID" },
    { NDS_SEARCH_ENTRY_MTS_GE, "Entry Modification Timestamp Greater or Equal" },
    { NDS_SEARCH_ENTRY_MTS_G, "Entry Modification Timestamp Greater" },
    { NDS_SEARCH_ENTRY_MTS_LE, "Entry Modification Timestamp Less or Equals" },
    { NDS_SEARCH_ENTRY_MTS_L, "Entry Modification Timestamp Less" },
    { NDS_SEARCH_ENTRY_MTS_EQ, "Entry Modification Timestamp Equals" },
    { NDS_SEARCH_ENTRY_MTS_EQ_APPROX, "Entry Modification Timestamp Equals Approximately" },
    { NDS_SEARCH_VALUE_MTS_GE, "Value Modification Timestamp Greater or Equal" },
    { NDS_SEARCH_VALUE_MTS_G, "Value Modification Timestamp Greater" },
    { NDS_SEARCH_VALUE_MTS_LE, "Value Modification Timestamp Less or Equals" },
    { NDS_SEARCH_VALUE_MTS_L, "Value Modification Timestamp Less" },
    { NDS_SEARCH_VALUE_MTS_EQ, "Value Modification Timestamp Equals" },
    { NDS_SEARCH_VALUE_MTS_EQ_APPROX, "Value Modification Timestamp Equals Approximately" },
    { NDS_SEARCH_ENTRY_CTS_GE, "Entry Creation Timestamp Greater or Equals" },
    { NDS_SEARCH_ENTRY_CTS_G, "Entry Creation Timestamp Greater" },
    { NDS_SEARCH_ENTRY_CTS_LE, "Entry Creation Timestamp Less or Equals" },
    { NDS_SEARCH_ENTRY_CTS_L, "Entry Creation Timestamp Less" },
    { NDS_SEARCH_ENTRY_CTS_EQ, "Entry Creation Timestamp Equals" },
    { NDS_SEARCH_ENTRY_CTS_EQ_APPROX, "Entry Creation Timestamp Equals Approximately" },
    { NDS_SEARCH_VALUE_CTS_GE, "Value Creation Timestamp Greater or Equals" },
    { NDS_SEARCH_VALUE_CTS_G, "Value Creation Timestamp Greater" },
    { NDS_SEARCH_VALUE_CTS_LE, "Value Creation Timestamp Less or Equals" },
    { NDS_SEARCH_VALUE_CTS_L, "Value Creation Timestamp Less" },
    { NDS_SEARCH_VALUE_CTS_EQ, "Value Creation Timestamp Equals" },
    { NDS_SEARCH_VALUE_CTS_EQ_APPROX, "Value Creation Timestamp Equals Approximately" },
    { NDS_SEARCH_EXTENSIBLE, "Extensible" },
    { NDS_SEARCH_ENTRY_SUBCOUNT_GE, "Entry SubCount Greater or Equals" },
    { NDS_SEARCH_ENTRY_SUBCOUNT_G, "Entry SubCount Greater" },
    { NDS_SEARCH_ENTRY_SUBCOUNT_LE, "Entry SubCount Less or Equals" },
    { NDS_SEARCH_ENTRY_SUBCOUNT_L, "Entry SubCount Less" },
    { NDS_SEARCH_ENTRY_SUBCOUNT_EQ, "Entry SubCount Equals" },
    {0, NULL }
};

static const value_string iterator_subverbs[] = {
    { IT_CLEAR, "Clear" },
    { IT_COPY, "Copy" },
    { IT_COUNT, "Count" },
    { IT_CREATE, "Create" },
    { IT_CURRENT, "Current" },
    { IT_DESTROY, "Destroy" },
    { IT_DONE, "Done" },
    { IT_FIRST, "First" },
    { IT_GETPOSITION, "Get Position" },
    { IT_LAST, "Last" },
    { IT_NEXT, "Next" },
    { IT_PREV, "Previous" },
    { IT_POSITION, "Position" },
    { IT_POSITION_IT, "Position Iterator" },
    { IT_SETINDEX, "Set Index" },
    { IT_SETFILTER, "Set Filter" },
    { IT_SKIP, "Skip" },
    { IT_TYPEDOWN, "Type Down" },
    { IT_ATFIRST, "At First" },
    { IT_ATEOF, "At End of File" },
    { IT_GETINDEX, "Get Index" },
    { IT_ISPOSITIONABLE, "Is Positionable" },
    { IT_ATBOF, "At Beginning of File" },
    { IT_ATLAST, "At Last" },
    { 0, NULL }
};


static const value_string nds_tuned_tags[] = {
    { 0, "RDN Hint" },
    { 1, "RDN History" },
    {0, NULL }
};

#if 0
static const value_string nds_scope_vals[] = {
    { 0, "Search Scope: 0x0000 - Examine base object only" },
    { 1, "Search Scope: 0x0001 - Search the immediate subordinates of the base object" },
    { 2, "Search Scope: 0x0002 - Search the base object and all of its subordinates" },
    { 3, "Search Scope: 0x0003 - Search the base objects and all objects in its partition (NDS version 8 or higher)" },
    {0, NULL }
};
#endif

static const value_string nds_tuned_item_tags[] = {
    { 0, "Single Item" },
    { 1, "Multiple Items" },
    {0, NULL }
};

static const value_string nds_tags[] = {
    { NDS_TAG_NO_SUCH_ENTRY,        "No Such Entry" },
    { NDS_TAG_LOCAL_ENTRY,          "Local Entry" },
    { NDS_TAG_REMOTE_ENTRY,         "Remote Entry" },
    { NDS_TAG_ALIAS_ENTRY,          "Alias Entry" },
    { NDS_TAG_REFERRAL_INFORMATION, "Referral Information" },
    { NDS_TAG_ENTRY_AND_REFERRALS,  "Entry and Referrals" },
    { 0, NULL }
};

static const range_string nds_info_type[] = {
    { 0x00000000, 0x00000000, "Attribute Names Only / " },
    { 0x00000001, 0x00000001, "Attribute Name & Value / " },
    { 0x00000002, 0x00000002, "Effective Privileges / " },
    { 0x00000003, 0x00000003, "Value Information / " },
    { 0x00000004, 0x00000004, "Abbreviated Value / " },
    { 0x00000005, 0xFFFFFFFF, "No Info Type Set" },
    { 0, 0, NULL }
};

static const value_string nds_kind_of_changes[] = {
    { 0x00000000, "Add Attribute" },
    { 0x00000001, "Remove Attribute" },
    { 0x00000002, "Add Value" },
    { 0x00000003, "Remove Value" },
    { 0x00000004, "Add Additional Value" },
    { 0x00000005, "Overwrite Value" },
    { 0x00000006, "Clear Attribute" },
    { 0x00000007, "Clear Value" },
    { 0, NULL }
};

static const value_string es_type[] = {
    { 0x00000000, "No type is specified" },
    { 0x00000001, "Unicode string" },
    { 0x00000002, "Partial name" },
    { 0x00000003, "Referrals" },
    { 0x00000004, "Tuned name" },
    { 0x00000005, "GUID attribute" },
    { 0x00000006, "Local entry ID" },
    { 0x00000007, "Number of defined entry specifiers" },
    { 0, NULL }
};

static const value_string ncp_rights_vals[] = {
    { 0x00, "No Rights"},
    { 0x01, "Read"},
    { 0x02, "Write"},
    { 0x03, "Read, Write"},
    { 0x04, "Deny Read"},
    { 0x05, "Read, Deny Read"},
    { 0x06, "Write, Deny Read"},
    { 0x07, "Read, Write, Deny Read"},
    { 0x08, "Deny Write"},
    { 0x09, "Read, Deny Write"},
    { 0x0a, "Write, Deny Write"},
    { 0x0b, "Read, Write, Deny Write"},
    { 0x0c, "Deny Read, Deny Write"},
    { 0x0d, "Read, Deny Read, Deny Write"},
    { 0x0e, "Write, Deny Read, Deny Write"},
    { 0x0f, "Read, Write, Deny Read, Deny Write"},
    { 0x10, "Compatibility"},
    { 0x11, "Read, Compatibility"},
    { 0x12, "Write, Compatibility"},
    { 0x13, "Read, Write, Compatibility"},
    { 0x14, "Deny Read, Compatibility"},
    { 0x15, "Read, Deny Read, Compatibility"},
    { 0x16, "Write, Deny Read, Compatibility"},
    { 0x17, "Read, Write, Deny Read, Compatibility"},
    { 0x18, "Deny Write, Compatibility"},
    { 0x19, "Read, Deny Write, Compatibility"},
    { 0x1a, "Write, Deny Write, Compatibility"},
    { 0x1b, "Read, Write, Deny Write, Compatibility"},
    { 0x1c, "Deny Read, Deny Write, Compatibility"},
    { 0x1d, "Read, Deny Read, Deny Write, Compatibility"},
    { 0x1e, "Write, Deny Read, Deny Write, Compatibility"},
    { 0x1f, "Read, Write, Deny Read, Deny Write, Compatibility"},
    { 0x40, "File Write Through"},
    { 0x41, "Read, File Write Through"},
    { 0x42, "Write, File Write Through"},
    { 0x43, "Read, Write, File Write Through"},
    { 0x44, "Deny Read, File Write Through"},
    { 0x45, "Read, Deny Read, File Write Through"},
    { 0x46, "Write, Deny Read, File Write Through"},
    { 0x47, "Read, Write, Deny Read, File Write Through"},
    { 0x48, "Deny Write, File Write Through"},
    { 0x49, "Read, Deny Write, File Write Through"},
    { 0x4a, "Write, Deny Write, File Write Through"},
    { 0x4b, "Read, Write, Deny Write, File Write Through"},
    { 0x4c, "Deny Read, Deny Write, File Write Through"},
    { 0x4d, "Read, Deny Read, Deny Write, File Write Through"},
    { 0x4e, "Write, Deny Read, Deny Write, File Write Through"},
    { 0x4f, "Read, Write, Deny Read, Deny Write, File Write Through"},
    { 0x50, "Compatibility, File Write Through"},
    { 0x51, "Read, Compatibility, File Write Through"},
    { 0x52, "Write, Compatibility, File Write Through"},
    { 0x53, "Read, Write, Compatibility, File Write Through"},
    { 0x54, "Deny Read, Compatibility, File Write Through"},
    { 0x55, "Read, Deny Read, Compatibility, File Write Through"},
    { 0x56, "Write, Deny Read, Compatibility, File Write Through"},
    { 0x57, "Read, Write, Deny Read, Compatibility, File Write Through"},
    { 0x58, "Deny Write, Compatibility, File Write Through"},
    { 0x59, "Read, Deny Write, Compatibility, File Write Through"},
    { 0x5a, "Write, Deny Write, Compatibility, File Write Through"},
    { 0x5b, "Read, Write, Deny Write, Compatibility, File Write Through"},
    { 0x5c, "Deny Read, Deny Write, Compatibility, File Write Through"},
    { 0x5d, "Read, Deny Read, Deny Write, Compatibility, File Write Through"},
    { 0x5e, "Write, Deny Read, Deny Write, Compatibility, File Write Through"},
    { 0x5f, "Read, Write, Deny Read, Deny Write, Compatibility, File Write Through"},
    { 0,    NULL }
};

static const value_string open_create_mode_vals[] = {
    { 0x01, "Open"},
    { 0x02, "Replace"},
    { 0x03, "Open, Replace"},
    { 0x08, "Create"},
    { 0x09, "Open, Create"},
    { 0x0a, "Replace, Create"},
    { 0x0b, "Open, Replace, Create"},
    { 0x20, "64-bit"},
    { 0x21, "Open, 64-bit"},
    { 0x22, "Replace, 64-bit"},
    { 0x23, "Open, Replace, 64-bit"},
    { 0x28, "Create, 64-bit"},
    { 0x29, "Open, Create, 64-bit"},
    { 0x2a, "Replace, Create, 64-bit"},
    { 0x2b, "Open, Replace, Create, 64-bit"},
    { 0x40, "Read Only"},
    { 0x41, "Open, Read Only"},
    { 0x42, "Replace, Read Only"},
    { 0x43, "Open, Replace, Read Only"},
    { 0x48, "Create, Read Only"},
    { 0x49, "Open, Create, Read Only"},
    { 0x4a, "Replace, Create, Read Only"},
    { 0x4b, "Open, Replace, Create, Read Only"},
    { 0x60, "64-bit, Read Only"},
    { 0x61, "Open, 64-bit, Read Only"},
    { 0x62, "Replace, 64-bit, Read Only"},
    { 0x63, "Open, Replace, 64-bit, Read Only"},
    { 0x68, "Create, 64-bit, Read Only"},
    { 0x69, "Open, Create, 64-bit, Read Only"},
    { 0x6a, "Replace, Create, 64-bit, Read Only"},
    { 0x6b, "Open, Replace, Create, 64-bit, Read Only"},
    { 0x80, "Op-Lock"},
    { 0x81, "Open, Op-Lock"},
    { 0x82, "Replace, Op-Lock"},
    { 0x83, "Open, Replace, Op-Lock"},
    { 0x88, "Create, Op-Lock"},
    { 0x89, "Open, Create, Op-Lock"},
    { 0x8a, "Replace, Create, Op-Lock"},
    { 0x8b, "Open, Replace, Create, Op-Lock"},
    { 0xa0, "64-bit, Op-Lock"},
    { 0xa1, "Open, 64-bit, Op-Lock"},
    { 0xa2, "Replace, 64-bit, Op-Lock"},
    { 0xa3, "Open, Replace, 64-bit, Op-Lock"},
    { 0xa8, "Create, 64-bit, Op-Lock"},
    { 0xa9, "Open, Create, 64-bit, Op-Lock"},
    { 0xaa, "Replace, Create, 64-bit, Op-Lock"},
    { 0xab, "Open, Replace, Create, 64-bit, Op-Lock"},
    { 0xc0, "Read Only, Op-Lock"},
    { 0xc1, "Open, Read Only, Op-Lock"},
    { 0xc2, "Replace, Read Only, Op-Lock"},
    { 0xc3, "Open, Replace, Read Only, Op-Lock"},
    { 0xc8, "Create, Read Only, Op-Lock"},
    { 0xc9, "Open, Create, Read Only, Op-Lock"},
    { 0xca, "Replace, Create, Read Only, Op-Lock"},
    { 0xcb, "Open, Replace, Create, Read Only, Op-Lock"},
    { 0xe0, "64-bit, Read Only, Op-Lock"},
    { 0xe1, "Open, 64-bit, Read Only, Op-Lock"},
    { 0xe2, "Replace, 64-bit, Read Only, Op-Lock"},
    { 0xe3, "Open, Replace, 64-bit, Read Only, Op-Lock"},
    { 0xe8, "Create, 64-bit, Read Only, Op-Lock"},
    { 0xe9, "Open, Create, 64-bit, Read Only, Op-Lock"},
    { 0xea, "Replace, Create, 64-bit, Read Only, Op-Lock"},
    { 0xeb, "Open, Replace, Create, 64-bit, Read Only, Op-Lock"},
    { 0,    NULL }
};

static const value_string open_create_action_vals[] = {
    { 0x01, "Opened"},
    { 0x02, "Created"},
    { 0x03, "Opened, Created"},
    { 0x04, "Replaced"},
    { 0x05, "Opened, Replaced"},
    { 0x06, "Created, Replaced"},
    { 0x07, "Opened, Created, Replaced"},
    { 0x08, "Compressed"},
    { 0x09, "Opened, Compressed"},
    { 0x0a, "Created, Compressed"},
    { 0x0b, "Opened, Created, Compressed"},
    { 0x0c, "Replaced, Compressed"},
    { 0x0d, "Opened, Replaced, Compressed"},
    { 0x0e, "Created, Replaced, Compressed"},
    { 0x0f, "Opened, Created, Replaced, Compressed"},
    { 0x80, "Read Only"},
    { 0x81, "Opened, Read Only"},
    { 0x82, "Created, Read Only"},
    { 0x83, "Opened, Created, Read Only"},
    { 0x84, "Replaced, Read Only"},
    { 0x85, "Opened, Replaced, Read Only"},
    { 0x86, "Created, Replaced, Read Only"},
    { 0x87, "Opened, Created, Replaced, Read Only"},
    { 0x88, "Compressed, Read Only"},
    { 0x89, "Opened, Compressed, Read Only"},
    { 0x8a, "Created, Compressed, Read Only"},
    { 0x8b, "Opened, Created, Compressed, Read Only"},
    { 0x8c, "Replaced, Compressed, Read Only"},
    { 0x8d, "Opened, Replaced, Compressed, Read Only"},
    { 0x8e, "Created, Replaced, Compressed, Read Only"},
    { 0x8f, "Opened, Created, Replaced, Compressed, Read Only"},
    { 0,    NULL }
};

static const value_string access_rights_vals[] = {
    { 0x0000, "No Rights"},
    { 0x0001, "Read"},
    { 0x0002, "Write"},
    { 0x0003, "Read, Write"},
    { 0x0004, "Open"},
    { 0x0005, "Read, Open"},
    { 0x0006, "Write, Open"},
    { 0x0007, "Read, Write, Open"},
    { 0x0008, "Create"},
    { 0x0009, "Read, Create"},
    { 0x000a, "Write, Create"},
    { 0x000b, "Read, Write, Create"},
    { 0x000c, "Open, Create"},
    { 0x000d, "Read, Open, Create"},
    { 0x000e, "Write, Open, Create"},
    { 0x000f, "Read, Write, Open, Create"},
    { 0x0010, "Delete"},
    { 0x0011, "Read, Delete"},
    { 0x0012, "Write, Delete"},
    { 0x0013, "Read, Write, Delete"},
    { 0x0014, "Open, Delete"},
    { 0x0015, "Read, Open, Delete"},
    { 0x0016, "Write, Open, Delete"},
    { 0x0017, "Read, Write, Open, Delete"},
    { 0x0018, "Create, Delete"},
    { 0x0019, "Read, Create, Delete"},
    { 0x001a, "Write, Create, Delete"},
    { 0x001b, "Read, Write, Create, Delete"},
    { 0x001c, "Open, Create, Delete"},
    { 0x001d, "Read, Open, Create, Delete"},
    { 0x001e, "Write, Open, Create, Delete"},
    { 0x001f, "Read, Write, Open, Create, Delete"},
    { 0x0020, "Parental"},
    { 0x0021, "Read, Parental"},
    { 0x0022, "Write, Parental"},
    { 0x0023, "Read, Write, Parental"},
    { 0x0024, "Open, Parental"},
    { 0x0025, "Read, Open, Parental"},
    { 0x0026, "Write, Open, Parental"},
    { 0x0027, "Read, Write, Open, Parental"},
    { 0x0028, "Create, Parental"},
    { 0x0029, "Read, Create, Parental"},
    { 0x002a, "Write, Create, Parental"},
    { 0x002b, "Read, Write, Create, Parental"},
    { 0x002c, "Open, Create, Parental"},
    { 0x002d, "Read, Open, Create, Parental"},
    { 0x002e, "Write, Open, Create, Parental"},
    { 0x002f, "Read, Write, Open, Create, Parental"},
    { 0x0030, "Delete, Parental"},
    { 0x0031, "Read, Delete, Parental"},
    { 0x0032, "Write, Delete, Parental"},
    { 0x0033, "Read, Write, Delete, Parental"},
    { 0x0034, "Open, Delete, Parental"},
    { 0x0035, "Read, Open, Delete, Parental"},
    { 0x0036, "Write, Open, Delete, Parental"},
    { 0x0037, "Read, Write, Open, Delete, Parental"},
    { 0x0038, "Create, Delete, Parental"},
    { 0x0039, "Read, Create, Delete, Parental"},
    { 0x003a, "Write, Create, Delete, Parental"},
    { 0x003b, "Read, Write, Create, Delete, Parental"},
    { 0x003c, "Open, Create, Delete, Parental"},
    { 0x003d, "Read, Open, Create, Delete, Parental"},
    { 0x003e, "Write, Open, Create, Delete, Parental"},
    { 0x003f, "Read, Write, Open, Create, Delete, Parental"},
    { 0x0040, "Search"},
    { 0x0041, "Read, Search"},
    { 0x0042, "Write, Search"},
    { 0x0043, "Read, Write, Search"},
    { 0x0044, "Open, Search"},
    { 0x0045, "Read, Open, Search"},
    { 0x0046, "Write, Open, Search"},
    { 0x0047, "Read, Write, Open, Search"},
    { 0x0048, "Create, Search"},
    { 0x0049, "Read, Create, Search"},
    { 0x004a, "Write, Create, Search"},
    { 0x004b, "Read, Write, Create, Search"},
    { 0x004c, "Open, Create, Search"},
    { 0x004d, "Read, Open, Create, Search"},
    { 0x004e, "Write, Open, Create, Search"},
    { 0x004f, "Read, Write, Open, Create, Search"},
    { 0x0050, "Delete, Search"},
    { 0x0051, "Read, Delete, Search"},
    { 0x0052, "Write, Delete, Search"},
    { 0x0053, "Read, Write, Delete, Search"},
    { 0x0054, "Open, Delete, Search"},
    { 0x0055, "Read, Open, Delete, Search"},
    { 0x0056, "Write, Open, Delete, Search"},
    { 0x0057, "Read, Write, Open, Delete, Search"},
    { 0x0058, "Create, Delete, Search"},
    { 0x0059, "Read, Create, Delete, Search"},
    { 0x005a, "Write, Create, Delete, Search"},
    { 0x005b, "Read, Write, Create, Delete, Search"},
    { 0x005c, "Open, Create, Delete, Search"},
    { 0x005d, "Read, Open, Create, Delete, Search"},
    { 0x005e, "Write, Open, Create, Delete, Search"},
    { 0x005f, "Read, Write, Open, Create, Delete, Search"},
    { 0x0060, "Parental, Search"},
    { 0x0061, "Read, Parental, Search"},
    { 0x0062, "Write, Parental, Search"},
    { 0x0063, "Read, Write, Parental, Search"},
    { 0x0064, "Open, Parental, Search"},
    { 0x0065, "Read, Open, Parental, Search"},
    { 0x0066, "Write, Open, Parental, Search"},
    { 0x0067, "Read, Write, Open, Parental, Search"},
    { 0x0068, "Create, Parental, Search"},
    { 0x0069, "Read, Create, Parental, Search"},
    { 0x006a, "Write, Create, Parental, Search"},
    { 0x006b, "Read, Write, Create, Parental, Search"},
    { 0x006c, "Open, Create, Parental, Search"},
    { 0x006d, "Read, Open, Create, Parental, Search"},
    { 0x006e, "Write, Open, Create, Parental, Search"},
    { 0x006f, "Read, Write, Open, Create, Parental, Search"},
    { 0x0070, "Delete, Parental, Search"},
    { 0x0071, "Read, Delete, Parental, Search"},
    { 0x0072, "Write, Delete, Parental, Search"},
    { 0x0073, "Read, Write, Delete, Parental, Search"},
    { 0x0074, "Open, Delete, Parental, Search"},
    { 0x0075, "Read, Open, Delete, Parental, Search"},
    { 0x0076, "Write, Open, Delete, Parental, Search"},
    { 0x0077, "Read, Write, Open, Delete, Parental, Search"},
    { 0x0078, "Create, Delete, Parental, Search"},
    { 0x0079, "Read, Create, Delete, Parental, Search"},
    { 0x007a, "Write, Create, Delete, Parental, Search"},
    { 0x007b, "Read, Write, Create, Delete, Parental, Search"},
    { 0x007c, "Open, Create, Delete, Parental, Search"},
    { 0x007d, "Read, Open, Create, Delete, Parental, Search"},
    { 0x007e, "Write, Open, Create, Delete, Parental, Search"},
    { 0x007f, "Read, Write, Open, Create, Delete, Parental, Search"},
    { 0x0080, "Modify"},
    { 0x0081, "Read, Modify"},
    { 0x0082, "Write, Modify"},
    { 0x0083, "Read, Write, Modify"},
    { 0x0084, "Open, Modify"},
    { 0x0085, "Read, Open, Modify"},
    { 0x0086, "Write, Open, Modify"},
    { 0x0087, "Read, Write, Open, Modify"},
    { 0x0088, "Create, Modify"},
    { 0x0089, "Read, Create, Modify"},
    { 0x008a, "Write, Create, Modify"},
    { 0x008b, "Read, Write, Create, Modify"},
    { 0x008c, "Open, Create, Modify"},
    { 0x008d, "Read, Open, Create, Modify"},
    { 0x008e, "Write, Open, Create, Modify"},
    { 0x008f, "Read, Write, Open, Create, Modify"},
    { 0x0090, "Delete, Modify"},
    { 0x0091, "Read, Delete, Modify"},
    { 0x0092, "Write, Delete, Modify"},
    { 0x0093, "Read, Write, Delete, Modify"},
    { 0x0094, "Open, Delete, Modify"},
    { 0x0095, "Read, Open, Delete, Modify"},
    { 0x0096, "Write, Open, Delete, Modify"},
    { 0x0097, "Read, Write, Open, Delete, Modify"},
    { 0x0098, "Create, Delete, Modify"},
    { 0x0099, "Read, Create, Delete, Modify"},
    { 0x009a, "Write, Create, Delete, Modify"},
    { 0x009b, "Read, Write, Create, Delete, Modify"},
    { 0x009c, "Open, Create, Delete, Modify"},
    { 0x009d, "Read, Open, Create, Delete, Modify"},
    { 0x009e, "Write, Open, Create, Delete, Modify"},
    { 0x009f, "Read, Write, Open, Create, Delete, Modify"},
    { 0x00a0, "Parental, Modify"},
    { 0x00a1, "Read, Parental, Modify"},
    { 0x00a2, "Write, Parental, Modify"},
    { 0x00a3, "Read, Write, Parental, Modify"},
    { 0x00a4, "Open, Parental, Modify"},
    { 0x00a5, "Read, Open, Parental, Modify"},
    { 0x00a6, "Write, Open, Parental, Modify"},
    { 0x00a7, "Read, Write, Open, Parental, Modify"},
    { 0x00a8, "Create, Parental, Modify"},
    { 0x00a9, "Read, Create, Parental, Modify"},
    { 0x00aa, "Write, Create, Parental, Modify"},
    { 0x00ab, "Read, Write, Create, Parental, Modify"},
    { 0x00ac, "Open, Create, Parental, Modify"},
    { 0x00ad, "Read, Open, Create, Parental, Modify"},
    { 0x00ae, "Write, Open, Create, Parental, Modify"},
    { 0x00af, "Read, Write, Open, Create, Parental, Modify"},
    { 0x00b0, "Delete, Parental, Modify"},
    { 0x00b1, "Read, Delete, Parental, Modify"},
    { 0x00b2, "Write, Delete, Parental, Modify"},
    { 0x00b3, "Read, Write, Delete, Parental, Modify"},
    { 0x00b4, "Open, Delete, Parental, Modify"},
    { 0x00b5, "Read, Open, Delete, Parental, Modify"},
    { 0x00b6, "Write, Open, Delete, Parental, Modify"},
    { 0x00b7, "Read, Write, Open, Delete, Parental, Modify"},
    { 0x00b8, "Create, Delete, Parental, Modify"},
    { 0x00b9, "Read, Create, Delete, Parental, Modify"},
    { 0x00ba, "Write, Create, Delete, Parental, Modify"},
    { 0x00bb, "Read, Write, Create, Delete, Parental, Modify"},
    { 0x00bc, "Open, Create, Delete, Parental, Modify"},
    { 0x00bd, "Read, Open, Create, Delete, Parental, Modify"},
    { 0x00be, "Write, Open, Create, Delete, Parental, Modify"},
    { 0x00bf, "Read, Write, Open, Create, Delete, Parental, Modify"},
    { 0x00c0, "Search, Modify"},
    { 0x00c1, "Read, Search, Modify"},
    { 0x00c2, "Write, Search, Modify"},
    { 0x00c3, "Read, Write, Search, Modify"},
    { 0x00c4, "Open, Search, Modify"},
    { 0x00c5, "Read, Open, Search, Modify"},
    { 0x00c6, "Write, Open, Search, Modify"},
    { 0x00c7, "Read, Write, Open, Search, Modify"},
    { 0x00c8, "Create, Search, Modify"},
    { 0x00c9, "Read, Create, Search, Modify"},
    { 0x00ca, "Write, Create, Search, Modify"},
    { 0x00cb, "Read, Write, Create, Search, Modify"},
    { 0x00cc, "Open, Create, Search, Modify"},
    { 0x00cd, "Read, Open, Create, Search, Modify"},
    { 0x00ce, "Write, Open, Create, Search, Modify"},
    { 0x00cf, "Read, Write, Open, Create, Search, Modify"},
    { 0x00d0, "Delete, Search, Modify"},
    { 0x00d1, "Read, Delete, Search, Modify"},
    { 0x00d2, "Write, Delete, Search, Modify"},
    { 0x00d3, "Read, Write, Delete, Search, Modify"},
    { 0x00d4, "Open, Delete, Search, Modify"},
    { 0x00d5, "Read, Open, Delete, Search, Modify"},
    { 0x00d6, "Write, Open, Delete, Search, Modify"},
    { 0x00d7, "Read, Write, Open, Delete, Search, Modify"},
    { 0x00d8, "Create, Delete, Search, Modify"},
    { 0x00d9, "Read, Create, Delete, Search, Modify"},
    { 0x00da, "Write, Create, Delete, Search, Modify"},
    { 0x00db, "Read, Write, Create, Delete, Search, Modify"},
    { 0x00dc, "Open, Create, Delete, Search, Modify"},
    { 0x00dd, "Read, Open, Create, Delete, Search, Modify"},
    { 0x00de, "Write, Open, Create, Delete, Search, Modify"},
    { 0x00df, "Read, Write, Open, Create, Delete, Search, Modify"},
    { 0x00e0, "Parental, Search, Modify"},
    { 0x00e1, "Read, Parental, Search, Modify"},
    { 0x00e2, "Write, Parental, Search, Modify"},
    { 0x00e3, "Read, Write, Parental, Search, Modify"},
    { 0x00e4, "Open, Parental, Search, Modify"},
    { 0x00e5, "Read, Open, Parental, Search, Modify"},
    { 0x00e6, "Write, Open, Parental, Search, Modify"},
    { 0x00e7, "Read, Write, Open, Parental, Search, Modify"},
    { 0x00e8, "Create, Parental, Search, Modify"},
    { 0x00e9, "Read, Create, Parental, Search, Modify"},
    { 0x00ea, "Write, Create, Parental, Search, Modify"},
    { 0x00eb, "Read, Write, Create, Parental, Search, Modify"},
    { 0x00ec, "Open, Create, Parental, Search, Modify"},
    { 0x00ed, "Read, Open, Create, Parental, Search, Modify"},
    { 0x00ee, "Write, Open, Create, Parental, Search, Modify"},
    { 0x00ef, "Read, Write, Open, Create, Parental, Search, Modify"},
    { 0x00f0, "Delete, Parental, Search, Modify"},
    { 0x00f1, "Read, Delete, Parental, Search, Modify"},
    { 0x00f2, "Write, Delete, Parental, Search, Modify"},
    { 0x00f3, "Read, Write, Delete, Parental, Search, Modify"},
    { 0x00f4, "Open, Delete, Parental, Search, Modify"},
    { 0x00f5, "Read, Open, Delete, Parental, Search, Modify"},
    { 0x00f6, "Write, Open, Delete, Parental, Search, Modify"},
    { 0x00f7, "Read, Write, Open, Delete, Parental, Search, Modify"},
    { 0x00f8, "Create, Delete, Parental, Search, Modify"},
    { 0x00f9, "Read, Create, Delete, Parental, Search, Modify"},
    { 0x00fa, "Write, Create, Delete, Parental, Search, Modify"},
    { 0x00fb, "Read, Write, Create, Delete, Parental, Search, Modify"},
    { 0x00fc, "Open, Create, Delete, Parental, Search, Modify"},
    { 0x00fd, "Read, Open, Create, Delete, Parental, Search, Modify"},
    { 0x00fe, "Write, Open, Create, Delete, Parental, Search, Modify"},
    { 0x00ff, "Read, Write, Open, Create, Delete, Parental, Search, Modify"},
    { 0x0100, "Supervisor"},
    { 0x0101, "Read, Supervisor"},
    { 0x0102, "Write, Supervisor"},
    { 0x0103, "Read, Write, Supervisor"},
    { 0x0104, "Open, Supervisor"},
    { 0x0105, "Read, Open, Supervisor"},
    { 0x0106, "Write, Open, Supervisor"},
    { 0x0107, "Read, Write, Open, Supervisor"},
    { 0x0108, "Create, Supervisor"},
    { 0x0109, "Read, Create, Supervisor"},
    { 0x010a, "Write, Create, Supervisor"},
    { 0x010b, "Read, Write, Create, Supervisor"},
    { 0x010c, "Open, Create, Supervisor"},
    { 0x010d, "Read, Open, Create, Supervisor"},
    { 0x010e, "Write, Open, Create, Supervisor"},
    { 0x010f, "Read, Write, Open, Create, Supervisor"},
    { 0x0110, "Delete, Supervisor"},
    { 0x0111, "Read, Delete, Supervisor"},
    { 0x0112, "Write, Delete, Supervisor"},
    { 0x0113, "Read, Write, Delete, Supervisor"},
    { 0x0114, "Open, Delete, Supervisor"},
    { 0x0115, "Read, Open, Delete, Supervisor"},
    { 0x0116, "Write, Open, Delete, Supervisor"},
    { 0x0117, "Read, Write, Open, Delete, Supervisor"},
    { 0x0118, "Create, Delete, Supervisor"},
    { 0x0119, "Read, Create, Delete, Supervisor"},
    { 0x011a, "Write, Create, Delete, Supervisor"},
    { 0x011b, "Read, Write, Create, Delete, Supervisor"},
    { 0x011c, "Open, Create, Delete, Supervisor"},
    { 0x011d, "Read, Open, Create, Delete, Supervisor"},
    { 0x011e, "Write, Open, Create, Delete, Supervisor"},
    { 0x011f, "Read, Write, Open, Create, Delete, Supervisor"},
    { 0x0120, "Parental, Supervisor"},
    { 0x0121, "Read, Parental, Supervisor"},
    { 0x0122, "Write, Parental, Supervisor"},
    { 0x0123, "Read, Write, Parental, Supervisor"},
    { 0x0124, "Open, Parental, Supervisor"},
    { 0x0125, "Read, Open, Parental, Supervisor"},
    { 0x0126, "Write, Open, Parental, Supervisor"},
    { 0x0127, "Read, Write, Open, Parental, Supervisor"},
    { 0x0128, "Create, Parental, Supervisor"},
    { 0x0129, "Read, Create, Parental, Supervisor"},
    { 0x012a, "Write, Create, Parental, Supervisor"},
    { 0x012b, "Read, Write, Create, Parental, Supervisor"},
    { 0x012c, "Open, Create, Parental, Supervisor"},
    { 0x012d, "Read, Open, Create, Parental, Supervisor"},
    { 0x012e, "Write, Open, Create, Parental, Supervisor"},
    { 0x012f, "Read, Write, Open, Create, Parental, Supervisor"},
    { 0x0130, "Delete, Parental, Supervisor"},
    { 0x0131, "Read, Delete, Parental, Supervisor"},
    { 0x0132, "Write, Delete, Parental, Supervisor"},
    { 0x0133, "Read, Write, Delete, Parental, Supervisor"},
    { 0x0134, "Open, Delete, Parental, Supervisor"},
    { 0x0135, "Read, Open, Delete, Parental, Supervisor"},
    { 0x0136, "Write, Open, Delete, Parental, Supervisor"},
    { 0x0137, "Read, Write, Open, Delete, Parental, Supervisor"},
    { 0x0138, "Create, Delete, Parental, Supervisor"},
    { 0x0139, "Read, Create, Delete, Parental, Supervisor"},
    { 0x013a, "Write, Create, Delete, Parental, Supervisor"},
    { 0x013b, "Read, Write, Create, Delete, Parental, Supervisor"},
    { 0x013c, "Open, Create, Delete, Parental, Supervisor"},
    { 0x013d, "Read, Open, Create, Delete, Parental, Supervisor"},
    { 0x013e, "Write, Open, Create, Delete, Parental, Supervisor"},
    { 0x013f, "Read, Write, Open, Create, Delete, Parental, Supervisor"},
    { 0x0140, "Search, Supervisor"},
    { 0x0141, "Read, Search, Supervisor"},
    { 0x0142, "Write, Search, Supervisor"},
    { 0x0143, "Read, Write, Search, Supervisor"},
    { 0x0144, "Open, Search, Supervisor"},
    { 0x0145, "Read, Open, Search, Supervisor"},
    { 0x0146, "Write, Open, Search, Supervisor"},
    { 0x0147, "Read, Write, Open, Search, Supervisor"},
    { 0x0148, "Create, Search, Supervisor"},
    { 0x0149, "Read, Create, Search, Supervisor"},
    { 0x014a, "Write, Create, Search, Supervisor"},
    { 0x014b, "Read, Write, Create, Search, Supervisor"},
    { 0x014c, "Open, Create, Search, Supervisor"},
    { 0x014d, "Read, Open, Create, Search, Supervisor"},
    { 0x014e, "Write, Open, Create, Search, Supervisor"},
    { 0x014f, "Read, Write, Open, Create, Search, Supervisor"},
    { 0x0150, "Delete, Search, Supervisor"},
    { 0x0151, "Read, Delete, Search, Supervisor"},
    { 0x0152, "Write, Delete, Search, Supervisor"},
    { 0x0153, "Read, Write, Delete, Search, Supervisor"},
    { 0x0154, "Open, Delete, Search, Supervisor"},
    { 0x0155, "Read, Open, Delete, Search, Supervisor"},
    { 0x0156, "Write, Open, Delete, Search, Supervisor"},
    { 0x0157, "Read, Write, Open, Delete, Search, Supervisor"},
    { 0x0158, "Create, Delete, Search, Supervisor"},
    { 0x0159, "Read, Create, Delete, Search, Supervisor"},
    { 0x015a, "Write, Create, Delete, Search, Supervisor"},
    { 0x015b, "Read, Write, Create, Delete, Search, Supervisor"},
    { 0x015c, "Open, Create, Delete, Search, Supervisor"},
    { 0x015d, "Read, Open, Create, Delete, Search, Supervisor"},
    { 0x015e, "Write, Open, Create, Delete, Search, Supervisor"},
    { 0x015f, "Read, Write, Open, Create, Delete, Search, Supervisor"},
    { 0x0160, "Parental, Search, Supervisor"},
    { 0x0161, "Read, Parental, Search, Supervisor"},
    { 0x0162, "Write, Parental, Search, Supervisor"},
    { 0x0163, "Read, Write, Parental, Search, Supervisor"},
    { 0x0164, "Open, Parental, Search, Supervisor"},
    { 0x0165, "Read, Open, Parental, Search, Supervisor"},
    { 0x0166, "Write, Open, Parental, Search, Supervisor"},
    { 0x0167, "Read, Write, Open, Parental, Search, Supervisor"},
    { 0x0168, "Create, Parental, Search, Supervisor"},
    { 0x0169, "Read, Create, Parental, Search, Supervisor"},
    { 0x016a, "Write, Create, Parental, Search, Supervisor"},
    { 0x016b, "Read, Write, Create, Parental, Search, Supervisor"},
    { 0x016c, "Open, Create, Parental, Search, Supervisor"},
    { 0x016d, "Read, Open, Create, Parental, Search, Supervisor"},
    { 0x016e, "Write, Open, Create, Parental, Search, Supervisor"},
    { 0x016f, "Read, Write, Open, Create, Parental, Search, Supervisor"},
    { 0x0170, "Delete, Parental, Search, Supervisor"},
    { 0x0171, "Read, Delete, Parental, Search, Supervisor"},
    { 0x0172, "Write, Delete, Parental, Search, Supervisor"},
    { 0x0173, "Read, Write, Delete, Parental, Search, Supervisor"},
    { 0x0174, "Open, Delete, Parental, Search, Supervisor"},
    { 0x0175, "Read, Open, Delete, Parental, Search, Supervisor"},
    { 0x0176, "Write, Open, Delete, Parental, Search, Supervisor"},
    { 0x0177, "Read, Write, Open, Delete, Parental, Search, Supervisor"},
    { 0x0178, "Create, Delete, Parental, Search, Supervisor"},
    { 0x0179, "Read, Create, Delete, Parental, Search, Supervisor"},
    { 0x017a, "Write, Create, Delete, Parental, Search, Supervisor"},
    { 0x017b, "Read, Write, Create, Delete, Parental, Search, Supervisor"},
    { 0x017c, "Open, Create, Delete, Parental, Search, Supervisor"},
    { 0x017d, "Read, Open, Create, Delete, Parental, Search, Supervisor"},
    { 0x017e, "Write, Open, Create, Delete, Parental, Search, Supervisor"},
    { 0x017f, "Read, Write, Open, Create, Delete, Parental, Search, Supervisor"},
    { 0x0180, "Modify, Supervisor"},
    { 0x0181, "Read, Modify, Supervisor"},
    { 0x0182, "Write, Modify, Supervisor"},
    { 0x0183, "Read, Write, Modify, Supervisor"},
    { 0x0184, "Open, Modify, Supervisor"},
    { 0x0185, "Read, Open, Modify, Supervisor"},
    { 0x0186, "Write, Open, Modify, Supervisor"},
    { 0x0187, "Read, Write, Open, Modify, Supervisor"},
    { 0x0188, "Create, Modify, Supervisor"},
    { 0x0189, "Read, Create, Modify, Supervisor"},
    { 0x018a, "Write, Create, Modify, Supervisor"},
    { 0x018b, "Read, Write, Create, Modify, Supervisor"},
    { 0x018c, "Open, Create, Modify, Supervisor"},
    { 0x018d, "Read, Open, Create, Modify, Supervisor"},
    { 0x018e, "Write, Open, Create, Modify, Supervisor"},
    { 0x018f, "Read, Write, Open, Create, Modify, Supervisor"},
    { 0x0190, "Delete, Modify, Supervisor"},
    { 0x0191, "Read, Delete, Modify, Supervisor"},
    { 0x0192, "Write, Delete, Modify, Supervisor"},
    { 0x0193, "Read, Write, Delete, Modify, Supervisor"},
    { 0x0194, "Open, Delete, Modify, Supervisor"},
    { 0x0195, "Read, Open, Delete, Modify, Supervisor"},
    { 0x0196, "Write, Open, Delete, Modify, Supervisor"},
    { 0x0197, "Read, Write, Open, Delete, Modify, Supervisor"},
    { 0x0198, "Create, Delete, Modify, Supervisor"},
    { 0x0199, "Read, Create, Delete, Modify, Supervisor"},
    { 0x019a, "Write, Create, Delete, Modify, Supervisor"},
    { 0x019b, "Read, Write, Create, Delete, Modify, Supervisor"},
    { 0x019c, "Open, Create, Delete, Modify, Supervisor"},
    { 0x019d, "Read, Open, Create, Delete, Modify, Supervisor"},
    { 0x019e, "Write, Open, Create, Delete, Modify, Supervisor"},
    { 0x019f, "Read, Write, Open, Create, Delete, Modify, Supervisor"},
    { 0x01a0, "Parental, Modify, Supervisor"},
    { 0x01a1, "Read, Parental, Modify, Supervisor"},
    { 0x01a2, "Write, Parental, Modify, Supervisor"},
    { 0x01a3, "Read, Write, Parental, Modify, Supervisor"},
    { 0x01a4, "Open, Parental, Modify, Supervisor"},
    { 0x01a5, "Read, Open, Parental, Modify, Supervisor"},
    { 0x01a6, "Write, Open, Parental, Modify, Supervisor"},
    { 0x01a7, "Read, Write, Open, Parental, Modify, Supervisor"},
    { 0x01a8, "Create, Parental, Modify, Supervisor"},
    { 0x01a9, "Read, Create, Parental, Modify, Supervisor"},
    { 0x01aa, "Write, Create, Parental, Modify, Supervisor"},
    { 0x01ab, "Read, Write, Create, Parental, Modify, Supervisor"},
    { 0x01ac, "Open, Create, Parental, Modify, Supervisor"},
    { 0x01ad, "Read, Open, Create, Parental, Modify, Supervisor"},
    { 0x01ae, "Write, Open, Create, Parental, Modify, Supervisor"},
    { 0x01af, "Read, Write, Open, Create, Parental, Modify, Supervisor"},
    { 0x01b0, "Delete, Parental, Modify, Supervisor"},
    { 0x01b1, "Read, Delete, Parental, Modify, Supervisor"},
    { 0x01b2, "Write, Delete, Parental, Modify, Supervisor"},
    { 0x01b3, "Read, Write, Delete, Parental, Modify, Supervisor"},
    { 0x01b4, "Open, Delete, Parental, Modify, Supervisor"},
    { 0x01b5, "Read, Open, Delete, Parental, Modify, Supervisor"},
    { 0x01b6, "Write, Open, Delete, Parental, Modify, Supervisor"},
    { 0x01b7, "Read, Write, Open, Delete, Parental, Modify, Supervisor"},
    { 0x01b8, "Create, Delete, Parental, Modify, Supervisor"},
    { 0x01b9, "Read, Create, Delete, Parental, Modify, Supervisor"},
    { 0x01ba, "Write, Create, Delete, Parental, Modify, Supervisor"},
    { 0x01bb, "Read, Write, Create, Delete, Parental, Modify, Supervisor"},
    { 0x01bc, "Open, Create, Delete, Parental, Modify, Supervisor"},
    { 0x01bd, "Read, Open, Create, Delete, Parental, Modify, Supervisor"},
    { 0x01be, "Write, Open, Create, Delete, Parental, Modify, Supervisor"},
    { 0x01bf, "Read, Write, Open, Create, Delete, Parental, Modify, Supervisor"},
    { 0x01c0, "Search, Modify, Supervisor"},
    { 0x01c1, "Read, Search, Modify, Supervisor"},
    { 0x01c2, "Write, Search, Modify, Supervisor"},
    { 0x01c3, "Read, Write, Search, Modify, Supervisor"},
    { 0x01c4, "Open, Search, Modify, Supervisor"},
    { 0x01c5, "Read, Open, Search, Modify, Supervisor"},
    { 0x01c6, "Write, Open, Search, Modify, Supervisor"},
    { 0x01c7, "Read, Write, Open, Search, Modify, Supervisor"},
    { 0x01c8, "Create, Search, Modify, Supervisor"},
    { 0x01c9, "Read, Create, Search, Modify, Supervisor"},
    { 0x01ca, "Write, Create, Search, Modify, Supervisor"},
    { 0x01cb, "Read, Write, Create, Search, Modify, Supervisor"},
    { 0x01cc, "Open, Create, Search, Modify, Supervisor"},
    { 0x01cd, "Read, Open, Create, Search, Modify, Supervisor"},
    { 0x01ce, "Write, Open, Create, Search, Modify, Supervisor"},
    { 0x01cf, "Read, Write, Open, Create, Search, Modify, Supervisor"},
    { 0x01d0, "Delete, Search, Modify, Supervisor"},
    { 0x01d1, "Read, Delete, Search, Modify, Supervisor"},
    { 0x01d2, "Write, Delete, Search, Modify, Supervisor"},
    { 0x01d3, "Read, Write, Delete, Search, Modify, Supervisor"},
    { 0x01d4, "Open, Delete, Search, Modify, Supervisor"},
    { 0x01d5, "Read, Open, Delete, Search, Modify, Supervisor"},
    { 0x01d6, "Write, Open, Delete, Search, Modify, Supervisor"},
    { 0x01d7, "Read, Write, Open, Delete, Search, Modify, Supervisor"},
    { 0x01d8, "Create, Delete, Search, Modify, Supervisor"},
    { 0x01d9, "Read, Create, Delete, Search, Modify, Supervisor"},
    { 0x01da, "Write, Create, Delete, Search, Modify, Supervisor"},
    { 0x01db, "Read, Write, Create, Delete, Search, Modify, Supervisor"},
    { 0x01dc, "Open, Create, Delete, Search, Modify, Supervisor"},
    { 0x01dd, "Read, Open, Create, Delete, Search, Modify, Supervisor"},
    { 0x01de, "Write, Open, Create, Delete, Search, Modify, Supervisor"},
    { 0x01df, "Read, Write, Open, Create, Delete, Search, Modify, Supervisor"},
    { 0x01e0, "Parental, Search, Modify, Supervisor"},
    { 0x01e1, "Read, Parental, Search, Modify, Supervisor"},
    { 0x01e2, "Write, Parental, Search, Modify, Supervisor"},
    { 0x01e3, "Read, Write, Parental, Search, Modify, Supervisor"},
    { 0x01e4, "Open, Parental, Search, Modify, Supervisor"},
    { 0x01e5, "Read, Open, Parental, Search, Modify, Supervisor"},
    { 0x01e6, "Write, Open, Parental, Search, Modify, Supervisor"},
    { 0x01e7, "Read, Write, Open, Parental, Search, Modify, Supervisor"},
    { 0x01e8, "Create, Parental, Search, Modify, Supervisor"},
    { 0x01e9, "Read, Create, Parental, Search, Modify, Supervisor"},
    { 0x01ea, "Write, Create, Parental, Search, Modify, Supervisor"},
    { 0x01eb, "Read, Write, Create, Parental, Search, Modify, Supervisor"},
    { 0x01ec, "Open, Create, Parental, Search, Modify, Supervisor"},
    { 0x01ed, "Read, Open, Create, Parental, Search, Modify, Supervisor"},
    { 0x01ee, "Write, Open, Create, Parental, Search, Modify, Supervisor"},
    { 0x01ef, "Read, Write, Open, Create, Parental, Search, Modify, Supervisor"},
    { 0x01f0, "Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f1, "Read, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f2, "Write, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f3, "Read, Write, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f4, "Open, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f5, "Read, Open, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f6, "Write, Open, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f7, "Read, Write, Open, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f8, "Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01f9, "Read, Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01fa, "Write, Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01fb, "Read, Write, Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01fc, "Open, Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01fd, "Read, Open, Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01fe, "Write, Open, Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0x01ff, "Read, Write, Open, Create, Delete, Parental, Search, Modify, Supervisor"},
    { 0,    NULL }
};


static const value_string nds_reply_errors[] = {
    { 0xffffffff, "(-1) Insufficient Space" },
    { 0xffffff89, "(-119) Buffer too Small" },
    { 0xffffff88, "(-120) RR Volume Flag Not Set" },
    { 0xffffff87, "(-121) No Items Found" },
    { 0xffffff86, "(-122) Connection Already Temporary" },
    { 0xffffff85, "(-123) Connection Already Logged In" },
    { 0xffffff84, "(-124) Connection Not Authenticated" },
    { 0xffffff83, "(-125) Connection Not Logged In" },
    { 0xffffff82, "(-126) NCP Boundary Check Failed" },
    { 0xffffff81, "(-127) Lock Waiting" },
    { 0xffffff80, "(-128) Lock Fail" },
    { 0xffffff7f, "(-129) Out of Handles" },
    { 0xffffff7e, "(-130) No Open Privilege" },
    { 0xffffff7d, "(-131) Hard IO Error" },
    { 0xffffff7c, "(-132) No Create Privilege" },
    { 0xffffff7b, "(-133) No Create Delete Privilege" },
    { 0xffffff7a, "(-134) Create Duplicate When Read Only" },
    { 0xffffff79, "(-135) Create File with Invalid Name" },
    { 0xffffff78, "(-136) Invalid File Handle" },
    { 0xffffff77, "(-137) No Search Privilege"   },
    { 0xffffff76, "(-138) No Delete Privilege" },
    { 0xffffff75, "(-139) No Rename Privilege" },
    { 0xffffff74, "(-140) No Set Privilege" },
    { 0xffffff73, "(-141) Some File in Use" },
    { 0xffffff72, "(-142) All File in Use" },
    { 0xffffff71, "(-143) Some Read Only" },
    { 0xffffff70, "(-144) All Read Only" },
    { 0xffffff6f, "(-145) Some names Exist" },
    { 0xffffff6e, "(-146) All Names Exist" },
    { 0xffffff6d, "(-147) No Read Privilege" },
    { 0xffffff6c, "(-148) No Write Privilege" },
    { 0xffffff6b, "(-149) File Detached" },
    { 0xffffff6a, "(-150) No Alloc Space/Target Not a Subdirectory/Insuffficient Memory" },
    { 0xffffff69, "(-151) No Spool Space" },
    { 0xffffff68, "(-152) Invalid Volume" },
    { 0xffffff67, "(-153) Directory Full" },
    { 0xffffff66, "(-154) Rename Across Volume" },
    { 0xffffff65, "(-155) Bad Directory Handle" },
    { 0xffffff64, "(-156) Invalid Path/No Such Extension" },
    { 0xffffff63, "(-157) No Directory Handles" },
    { 0xffffff62, "(-158) Bad File Name" },
    { 0xffffff61, "(-159) Directory Active" },
    { 0xffffff60, "(-160) Directory Not Empty" },
    { 0xffffff5f, "(-161) Directory IO Error" },
    { 0xffffff5e, "(-162) IO Locked" },
    { 0xffffff5d, "(-163) Transaction Restarted" },
    { 0xffffff5c, "(-164) Rename Directory Invalid" },
    { 0xffffff5b, "(-165) Invalid Open/Create Mode" },
    { 0xffffff5a, "(-166) Already in Use" },
    { 0xffffff59, "(-167) Invalid Resource Tag" },
    { 0xffffff58, "(-168) Access Denied" },
    { 0xffffff44, "(-188) Login Signing Required" },
    { 0xffffff43, "(-189) Login Encryption Required" },
    { 0xffffff42, "(-190) Invalid Data Stream" },
    { 0xffffff41, "(-191) Invalid Name Space" },
    { 0xffffff40, "(-192) No Accounting Privileges" },
    { 0xffffff3f, "(-193) No Account Balance" },
    { 0xffffff3e, "(-194) Credit Limit Exceeded" },
    { 0xffffff3d, "(-195) Too Many Holds" },
    { 0xffffff3c, "(-196) Accounting Disabled" },
    { 0xffffff3b, "(-197) Intruder Login Lockout" },
    { 0xffffff3a, "(-198) No Console Rights" },
    { 0xffffff30, "(-208) Queue IO Failure" },
    { 0xffffff2f, "(-209) No Queue" },
    { 0xffffff2e, "(-210) No Queue Server" },
    { 0xffffff2d, "(-211) No Queue Rights" },
    { 0xffffff2c, "(-212) Queue Full" },
    { 0xffffff2b, "(-213) No Queue Job" },
    { 0xffffff2a, "(-214) No Queue Job Rights/Unencrypted Not Allowed" },
    { 0xffffff29, "(-215) Queue In Service/Duplicate Password" },
    { 0xffffff28, "(-216) Queue Not Active/Password Too Short" },
    { 0xffffff27, "(-217) Queue Station Not Server/Maximum Logins Exceeded" },
    { 0xffffff26, "(-218) Queue Halted/Bad Login Time" },
    { 0xffffff25, "(-219) Queue Maximum Servers/Node Address Violation" },
    { 0xffffff24, "(-220) Login Account Expired" },
    { 0xffffff22, "(-222) Bad Password" },
    { 0xffffff21, "(-223) Password Expired" },
    { 0xffffff20, "(-224) No Login Connection Available" },
    { 0xffffff18, "(-232) Write to Group Property" },
    { 0xffffff17, "(-233) Member Already Exists" },
    { 0xffffff16, "(-234) No Such Member" },
    { 0xffffff15, "(-235) Property Not Group" },
    { 0xffffff14, "(-236) No Such Value Set" },
    { 0xffffff13, "(-237) Property Already Exists" },
    { 0xffffff12, "(-238) Object Already Exists" },
    { 0xffffff11, "(-239) Illegal Name" },
    { 0xffffff10, "(-240) Illegal Wildcard" },
    { 0xffffff0f, "(-241) Bindery Security" },
    { 0xffffff0e, "(-242) No Object Read Rights" },
    { 0xffffff0d, "(-243) No Object Rename Rights" },
    { 0xffffff0c, "(-244) No Object Delete Rights" },
    { 0xffffff0b, "(-245) No Object Create Rights" },
    { 0xffffff0a, "(-246) No Property Delete Rights" },
    { 0xffffff09, "(-247) No Property Create Rights" },
    { 0xffffff08, "(-248) No Property Write Rights" },
    { 0xffffff07, "(-249) No Property Read Rights" },
    { 0xffffff06, "(-250) Temp Remap" },
    { 0xffffff05, "(-251) Unknown Request/No Such Property" },
    { 0xffffff04, "(-252) Message Queue Full/Target Already Has Message/No Such Object" },
    { 0xffffff03, "(-253) Bad Station Number" },
    { 0xffffff02, "(-254) Bindery Locked/Directory Locked/Spool Delete/Trustee not Found/Timeout" },
    { 0xffffff01, "(-255) Hard Failure" },
    { 0xfffffed3, "(-301) Not Enough Memory" },
    { 0xfffffed2, "(-302) Bad Key" },
    { 0xfffffed1, "(-303) Bad Context" },
    { 0xfffffed0, "(-304) Buffer Full" },
    { 0xfffffecf, "(-305) List Empty" },
    { 0xfffffece, "(-306) Bad Syntax"   },
    { 0xfffffecd, "(-307) Buffer Empty" },
    { 0xfffffecc, "(-308) Bad Verb" },
    { 0xfffffecb, "(-309) Expected Identifier" },
    { 0xfffffeca, "(-310) Expected Equals" },
    { 0xfffffec9, "(-311) Attribute Type Expected" },
    { 0xfffffec8, "(-312) Attribute Type Not Expected" },
    { 0xfffffec7, "(-313) Filter Tree Empty" },
    { 0xfffffec6, "(-314) Invalid Object Name" },
    { 0xfffffec5, "(-315) Expected RDN Delimiter" },
    { 0xfffffec4, "(-316) Too Many Tokens" },
    { 0xfffffec3, "(-317) Inconsistent MultiAVA" },
    { 0xfffffec2, "(-318) Country Name Too Long" },
    { 0xfffffec1, "(-319) Internal Error" },
    { 0xfffffec0, "(-320) Can't Add Root" },
    { 0xfffffebf, "(-321) Unable to Attach" },
    { 0xfffffebe, "(-322) Invalid Iteration Handle" },
    { 0xfffffebd, "(-323) Buffer Zero Length" },
    { 0xfffffebc, "(-324) Invalid Replica Type" },
    { 0xfffffebb, "(-325) Invalid Attribute Syntax" },
    { 0xfffffeba, "(-326) Invalid Filter Syntax" },
    { 0xfffffeb8, "(-328) Unicode Error during Context Creation" },
    { 0xfffffeb7, "(-329) Invalid Union Tag" },
    { 0xfffffeb6, "(-330) Invalid Server Response" },
    { 0xfffffeb5, "(-331) Null Pointer" },
    { 0xfffffeb4, "(-332) No Server Found" },
    { 0xfffffeb3, "(-333) No Connection" },
    { 0xfffffeb2, "(-334) RDN Too Long" },
    { 0xfffffeb1, "(-335) Duplicate Type" },
    { 0xfffffeb0, "(-336) Data Store Failure" },
    { 0xfffffeaf, "(-337) Not Logged In" },
    { 0xfffffeae, "(-338) Invalid Password Characters" },
    { 0xfffffead, "(-339) Failed Server Authentication" },
    { 0xfffffeac, "(-340) Transport Failed" },
    { 0xfffffeab, "(-341) No Such Syntax" },
    { 0xfffffeaa, "(-342) Invalid DS Name" },
    { 0xfffffea9, "(-343) Attribute Name Too Long" },
    { 0xfffffea8, "(-344) Invalid TDS" },
    { 0xfffffea7, "(-345) Invalid DS Version" },
    { 0xfffffea6, "(-346) Unicode Translation" },
    { 0xfffffea5, "(-347) Schema Name Too Long" },
    { 0xfffffea4, "(-348) Unicode File Not Found" },
    { 0xfffffea3, "(-349) Unicode Already Loaded" },
    { 0xfffffea2, "(-350) Not Context Owner" },
    { 0xfffffea1, "(-351) Attempt to Authenticate" },
    { 0xfffffea0, "(-352) No Writable Replicas" },
    { 0xfffffe9f, "(-353) DN Too Long" },
    { 0xfffffe9e, "(-354) Rename Not Allowed" },
    { 0xfffffe9d, "(-355) Not NDS for NT" },
    { 0xfffffe9c, "(-356) NDS for NT - No Domain" },
    { 0xfffffe9b, "(-357) NDS for NT - Sync Disabled" },
    { 0xfffffe9a, "(-358) Iterator Invalid Handle" },
    { 0xfffffe99, "(-359) Iterator Invalid Position" },
    { 0xfffffe98, "(-360) Iterator Invalid Search Data" },
    { 0xfffffe97, "(-361) Iterator Invalid Scope" },
    { 0xfffffda7, "(-601) No Such Entry" },
    { 0xfffffda6, "(-602) No Such Value" },
    { 0xfffffda5, "(-603) No Such Attribute" },
    { 0xfffffda4, "(-604) No Such Class" },
    { 0xfffffda3, "(-605) No Such Partition" },
    { 0xfffffda2, "(-606) Entry Already Exists" },
    { 0xfffffda1, "(-607) Not Effective Class" },
    { 0xfffffda0, "(-608) Illegal Attribute" },
    { 0xfffffd9f, "(-609) Missing Mandatory" },
    { 0xfffffd9e, "(-610) Illegal DS Name" },
    { 0xfffffd9d, "(-611) Illegal Containment" },
    { 0xfffffd9c, "(-612) Can't Have Multiple Values" },
    { 0xfffffd9b, "(-613) Syntax Violation" },
    { 0xfffffd9a, "(-614) Duplicate Value" },
    { 0xfffffd99, "(-615) Attribute Already Exists" },
    { 0xfffffd98, "(-616) Maximum Entries Exist" },
    { 0xfffffd97, "(-617) Database Format" },
    { 0xfffffd96, "(-618) Inconsistent Database" },
    { 0xfffffd95, "(-619) Invalid Comparison" },
    { 0xfffffd94, "(-620) Comparison Failed" },
    { 0xfffffd93, "(-621) Transaction Tracking Disabled" },
    { 0xfffffd92, "(-622) Invalid Transport" },
    { 0xfffffd91, "(-623) Syntax Invalid in Name" },
    { 0xfffffd90, "(-624) Replica Already Exists" },
    { 0xfffffd8f, "(-625) Transport Failure" },
    { 0xfffffd8e, "(-626) All Referrals Failed" },
    { 0xfffffd8d, "(-627) Can't Remove Naming Value" },
    { 0xfffffd8c, "(-628) Object Class Violation" },
    { 0xfffffd8b, "(-629) Entry is Not Leaf" },
    { 0xfffffd8a, "(-630) Different Tree" },
    { 0xfffffd89, "(-631) Illegal Replica Type" },
    { 0xfffffd88, "(-632) System Failure" },
    { 0xfffffd87, "(-633) Invalid Entry for Root" },
    { 0xfffffd86, "(-634) No Referrals" },
    { 0xfffffd85, "(-635) Remote Failure" },
    { 0xfffffd84, "(-636) Unreachable Server" },
    { 0xfffffd83, "(-637) Previous Move in Progress" },
    { 0xfffffd82, "(-638) No Character Mapping" },
    { 0xfffffd81, "(-639) Incomplete Authentication" },
    { 0xfffffd80, "(-640) Invalid Certificate" },
    { 0xfffffd7f, "(-641) Invalid Request" },
    { 0xfffffd7e, "(-642) Invalid Iteration" },
    { 0xfffffd7d, "(-643) Schema is Non-removable" },
    { 0xfffffd7c, "(-644) Schema is in Use" },
    { 0xfffffd7b, "(-645) Class Already Exists" },
    { 0xfffffd7a, "(-646) Bad Naming Attributes" },
    { 0xfffffd79, "(-647) Not Root Partition" },
    { 0xfffffd78, "(-648) Insufficient Stack" },
    { 0xfffffd77, "(-649) Insufficient Buffer" },
    { 0xfffffd76, "(-650) Ambiguous Containment" },
    { 0xfffffd75, "(-651) Ambiguous Naming" },
    { 0xfffffd74, "(-652) Duplicate Mandatory" },
    { 0xfffffd73, "(-653) Duplicate Optional" },
    { 0xfffffd72, "(-654) Partition Busy" },
    { 0xfffffd71, "(-655) Multiple Replicas" },
    { 0xfffffd70, "(-656) Crucial Replica" },
    { 0xfffffd6f, "(-657) Schema Sync in Progress" },
    { 0xfffffd6e, "(-658) Skulk in Progress" },
    { 0xfffffd6d, "(-659) Time Not Synchronized" },
    { 0xfffffd6c, "(-660) Record in Use" },
    { 0xfffffd6b, "(-661) DS Volume Not Mounted" },
    { 0xfffffd6a, "(-662) DS Volume IO Failure" },
    { 0xfffffd69, "(-663) DS Locked" },
    { 0xfffffd68, "(-664) Old Epoch" },
    { 0xfffffd67, "(-665) New Epoch" },
    { 0xfffffd66, "(-666) Incompatible DS Version" },
    { 0xfffffd65, "(-667) Partition Root" },
    { 0xfffffd64, "(-668) Entry Not Container" },
    { 0xfffffd63, "(-669) Failed Authentication" },
    { 0xfffffd62, "(-670) Invalid Context" },
    { 0xfffffd61, "(-671) No Such Parent" },
    { 0xfffffd60, "(-672) No Access" },
    { 0xfffffd5f, "(-673) Replica Not On" },
    { 0xfffffd5e, "(-674) Invalid Name Service" },
    { 0xfffffd5d, "(-675) Invalid Task" },
    { 0xfffffd5c, "(-676) Invalid Connection Handle" },
    { 0xfffffd5b, "(-677) Invalid Identity" },
    { 0xfffffd5a, "(-678) Duplicate ACL" },
    { 0xfffffd59, "(-679) Partition Already Exists" },
    { 0xfffffd58, "(-680) Transport Modified" },
    { 0xfffffd57, "(-681) Alias of an Alias" },
    { 0xfffffd56, "(-682) Auditing Failed" },
    { 0xfffffd55, "(-683) Invalid API Version" },
    { 0xfffffd54, "(-684) Secure NCP Violation" },
    { 0xfffffd53, "(-685) Move in Progress" },
    { 0xfffffd52, "(-686) Not a Leaf Partition" },
    { 0xfffffd51, "(-687) Cannot Abort" },
    { 0xfffffd50, "(-688) Cache Overflow" },
    { 0xfffffd4f, "(-689) Invalid Subordinate Count" },
    { 0xfffffd4e, "(-690) Invalid RDN" },
    { 0xfffffd4d, "(-691) Modification Time Not Current" },
    { 0xfffffd4c, "(-692) Incorrect Base Class" },
    { 0xfffffd4b, "(-693) Missing Reference" },
    { 0xfffffd4a, "(-694) Lost Entry" },
    { 0xfffffd49, "(-695) Agent Already Registered" },
    { 0xfffffd48, "(-696) DS Loader Busy" },
    { 0xfffffd47, "(-697) DS Cannot Reload" },
    { 0xfffffd46, "(-698) Replica in Skulk" },
    { 0xfffffd45, "(-699) Fatal" },
    { 0xfffffd44, "(-700) Obsolete API" },
    { 0xfffffd43, "(-701) Synchronization Disabled" },
    { 0xfffffd42, "(-702) Invalid Parameter" },
    { 0xfffffd41, "(-703) Duplicate Template" },
    { 0xfffffd40, "(-704) No Master Replica" },
    { 0xfffffd3f, "(-705) Duplicate Containment" },
    { 0xfffffd3e, "(-706) Not a Sibling" },
    { 0xfffffd3d, "(-707) Invalid Signature" },
    { 0xfffffd3c, "(-708) Invalid Response" },
    { 0xfffffd3b, "(-709) Insufficient Sockets" },
    { 0xfffffd3a, "(-710) Database Read Fail" },
    { 0xfffffd39, "(-711) Invalid Code Page" },
    { 0xfffffd38, "(-712) Invalid Escape Character" },
    { 0xfffffd37, "(-713) Invalid Delimiters" },
    { 0xfffffd36, "(-714) Not Implemented" },
    { 0xfffffd35, "(-715) Checksum Failure" },
    { 0xfffffd34, "(-716) Checksumming Not Supported" },
    { 0xfffffd33, "(-717) CRC Failure" },
    { 0xfffffd32, "(-718) Invalid Entry Handle" },
    { 0xfffffd31, "(-719) Invalid Value Handle" },
    { 0xfffffd30, "(-720) Connection Denied" },
    { 0xfffffd2f, "(-721) No Such Federation Link" },
    { 0xfffffd2e, "(-722) Operetational Schema Mismatch" },
    { 0xfffffd2d, "(-723) Stream Not Found" },
    { 0xfffffd2c, "(-724) DClient Unavailable" },
    { 0xfffffd2b, "(-725) MASV No Access" },
    { 0xfffffd2a, "(-726) MASV Invalid Request" },
    { 0xfffffd29, "(-727) MASV Failure" },
    { 0xfffffd28, "(-728) MASV Already Exists" },
    { 0xfffffd27, "(-729) MASV Not Found" },
    { 0xfffffd26, "(-730) MASV Bad Range" },
    { 0xfffffd25, "(-731) Value Data" },
    { 0xfffffd24, "(-732) Database Locked" },
    { 0xfffffd21, "(-735) Nothing to Abort" },
    { 0xfffffd20, "(-736) End of Stream" },
    { 0xfffffd1f, "(-737) No Such Template" },
    { 0xfffffd1e, "(-738) SAS Locked" },
    { 0xfffffd1d, "(-739) Invalid SAS Version" },
    { 0xfffffd1c, "(-740) SAS Already Registered" },
    { 0xfffffd1b, "(-741) Name Type Not Supported" },
    { 0xfffffd1a, "(-742) Wrong DS Version" },
    { 0xfffffd19, "(-743) Invalid Control Function" },
    { 0xfffffd18, "(-744) Invalid Control State" },
    { 0xfffffd17, "(-745) Cache in Use" },
    { 0xfffffd16, "(-746) Zero Creation Time" },
    { 0xfffffd15, "(-747) Would Block" },
    { 0xfffffd14, "(-748) Connection Timeout" },
    { 0xfffffd13, "(-749) Too Many Referrals" },
    { 0xfffffd12, "(-750) Operation Cancelled" },
    { 0xfffffd11, "(-751) Unknown Target" },
    { 0xfffffd10, "(-752) GUID Failure" },
    { 0xfffffd0f, "(-753) Incompatible OS" },
    { 0xfffffd0e, "(-754) Callback Cancel" },
    { 0xfffffd0d, "(-755) Invalid Synchronization Data" },
    { 0xfffffd0c, "(-756) Stream Exists" },
    { 0xfffffd0b, "(-757) Auxiliary Has Containment" },
    { 0xfffffd0a, "(-758) Auxiliary Not Container" },
    { 0xfffffd09, "(-759) Auxiliary Not Effective" },
    { 0xfffffd08, "(-760) Auxiliary On Alias" },
    { 0xfffffd07, "(-761) Have Seen State" },
    { 0xfffffd06, "(-762) Verb Locked" },
    { 0xfffffd05, "(-763) Verb Exceeds Table Length" },
    { 0xfffffd04, "(-764) BOF Hit" },
    { 0xfffffd03, "(-765) EOF Hit" },
    { 0xfffffd02, "(-766) Incompatible Replica Version" },
    { 0xfffffd01, "(-767) Query Timeout" },
    { 0xfffffd00, "(-768) Query Maximum Count" },
    { 0xfffffcff, "(-769) Duplicate Naming" },
    { 0xfffffcfe, "(-770) No Transaction Active" },
    { 0xfffffcfd, "(-771) Transaction Active" },
    { 0xfffffcfc, "(-772) Illegal Transaction Operation" },
    { 0xfffffcfb, "(-773) Iterator Syntax" },
    { 0xfffffcfa, "(-774) Repairing DIB" },
    { 0xfffffcf9, "(-775) Invalid OID Format" },
    { 0xfffffcf8, "(-776) Attempted to perform an NDS operation, and the DS agent on this server is closing" },
    { 0xfffffcf7, "(-777) Attempted to modify an object's attribute that is not stored on the sparse replica" },
    { 0xfffffcf6, "(-778) VpVector and VpvUser which must be correlated, are out of sync" },
    { 0xfffffcf5, "(-779) Error Cannot Go Remote" },
    { 0xfffffcf4, "(-780) Request not Supported" },
    { 0xfffffcf3, "(-781) Entry Not Local" },
    { 0xfffffcf2, "(-782) Root Unreachable" },
    { 0xfffffcf1, "(-783) VRDIM Not Initialized" },
    { 0xfffffcf0, "(-784) Wait Timeout" },
    { 0xfffffcef, "(-785) DIB Error" },
    { 0xfffffcee, "(-786) DIB IO Failure" },
    { 0xfffffced, "(-787) Illegal Schema Attribute" },
    { 0xfffffcec, "(-788) Error Schema Partition" },
    { 0xfffffceb, "(-789) Invalid Template" },
    { 0xfffffcea, "(-790) Error Opening File" },
    { 0xfffffce9, "(-791) Error Direct Opening File" },
    { 0xfffffce8, "(-792) Error Creating File" },
    { 0xfffffce7, "(-793) Error Direct Creating File" },
    { 0xfffffce6, "(-794) Error Reading File" },
    { 0xfffffce5, "(-795) Error Direct Reading File" },
    { 0xfffffce4, "(-796) Error Writing File" },
    { 0xfffffce3, "(-797) Error Direct Writing File" },
    { 0xfffffce2, "(-798) Error Positioning in File" },
    { 0xfffffce1, "(-799) Error Getting File Size" },
    { 0xffffe88f, "(-6001) Error Truncating File" },
    { 0xffffe88e, "(-6002) Error Parsing File Name" },
    { 0xffffe88d, "(-6003) Error Closing File" },
    { 0xffffe88c, "(-6004) Error Getting File Info" },
    { 0xffffe88b, "(-6005) Error Expanding File" },
    { 0xffffe88a, "(-6006) Error Getting Free Blocks" },
    { 0xffffe889, "(-6007) Error Checking File Existence" },
    { 0xffffe888, "(-6008) Error Deleting File" },
    { 0xffffe887, "(-6009) Error Renaming File" },
    { 0xffffe886, "(-6010) Error Initializing IO System" },
    { 0xffffe885, "(-6011) Error Flushing File" },
    { 0xffffe884, "(-6012) Error Setting Up for Read" },
    { 0xffffe883, "(-6013) Error Setting up for Write" },
    { 0xffffe882, "(-6014) Error Old View" },
    { 0xffffe881, "(-6015) Server in Skulk" },
    { 0xffffe880, "(-6016) Error Returning Partial Results" },
    { 0xffffe87f, "(-6017) No Such Schema" },
    { 0xffffe87e, "(-6018) Serial Number Mismatch" },
    { 0xffffe87d, "(-6019) Bad Referral Database Serial Number" },
    { 0xffffe87c, "(-6020) Bad Referral Serial Number" },
    { 0xffffe87b, "(-6021) Invalid File Sequence" },
    { 0xffffe87a, "(-6022) Error Referral Trans Gap" },
    { 0xffffe879, "(-6023) Bad Referral File Number" },
    { 0xffffe878, "(-6024) Referral File Not Found" },
    { 0xffffe877, "(-6025) Error Backup Active" },
    { 0xffffe876, "(-6026) Referral Device Full" },
    { 0xffffe875, "(-6027) Unsupported Version" },
    { 0xffffe874, "(-6028) Error Must Wait Checkpoint" },
    { 0xffffe873, "(-6029) Attribute Maintenance in Progress" },
    { 0xffffe872, "(-6030) Error Abort Transaction" },
    { 0xffff0000, "Ok" },
    { 0x0000, "Ok" },
    { 0, NULL }
};

#define NDS_PTYPE_IPX           0x00000000
#define NDS_PTYPE_IP            0x00000001
#define NDS_PTYPE_SDLC          0x00000002
#define NDS_PTYPE_TR_ON_ETH     0x00000003
#define NDS_PTYPE_OSI           0x00000004
#define NDS_PTYPE_APPLETALK     0x00000005
#define NDS_PTYPE_NETBEUI       0x00000006
#define NDS_PTYPE_SOCKETADDRESS 0x00000007
#define NDS_PTYPE_UDP           0x00000008
#define NDS_PTYPE_TCP           0x00000009
#define NDS_PTYPE_UDPv6         0x0000000a
#define NDS_PTYPE_TCPv6         0x0000000b
#define NDS_PTYPE_INTERNAL      0x0000000c
#define NDS_PTYPE_URL           0x0000000d
#define NDS_PTYPE_DNS           0x0000000e
#define NDS_PTYPE_CNT           0x0000000f

static const value_string nds_protocol_type[] = {
    { NDS_PTYPE_IPX,           "(IPX Protocol)" },
    { NDS_PTYPE_IP,            "(IP Protocol)" },
    { NDS_PTYPE_SDLC,          "(SDLC Protocol)" },
    { NDS_PTYPE_TR_ON_ETH,     "(TokenRing on Ethernet Protocol)" },
    { NDS_PTYPE_OSI,           "(OSI Protocol)" },
    { NDS_PTYPE_APPLETALK,     "(AppleTalk Protocol)" },
    { NDS_PTYPE_NETBEUI,       "(NetBEUI Protocol)" },
    { NDS_PTYPE_SOCKETADDRESS, "(Socket Address Protocol)" },
    { NDS_PTYPE_UDP,           "(UDP Protocol)" },
    { NDS_PTYPE_TCP,           "(TCP Protocol)" },
    { NDS_PTYPE_UDPv6,         "(UDP v6 Protocol)" },
    { NDS_PTYPE_TCPv6,         "(TCP v6 Protocol)" },
    { NDS_PTYPE_INTERNAL,      "(Internal Protocol)" },
    { NDS_PTYPE_URL,           "(URL Protocol)" },
    { NDS_PTYPE_DNS,           "(DNS Protocol)" },
    { NDS_PTYPE_CNT,           "(Number of protocol types defined)" },
    { 0, NULL }
};


static const value_string nds_syntax[] = {
    { 0x00000000, "Unknown Syntax" },
    { 0x00000001, "Distinguished Name" },
    { 0x00000002, "Case Sensitive Unicode String" },
    { 0x00000003, "Non Case Sensitive Unicode String" },
    { 0x00000004, "Printable String" },
    { 0x00000005, "Numeric String" },
    { 0x00000006, "Case Insensitive List" },
    { 0x00000007, "Boolean" },
    { 0x00000008, "Signed Integer" },
    { 0x00000009, "Binary String" },
    { 0x0000000a, "Telephone Number" },
    { 0x0000000b, "Fax Number" },
    { 0x0000000c, "Network Address" },
    { 0x0000000d, "Binary String List" },
    { 0x0000000e, "Email Address" },
    { 0x0000000f, "File System Path" },
    { 0x00000010, "Replica Pointer" },
    { 0x00000011, "Object ACL" },
    { 0x00000012, "Postal Address" },
    { 0x00000013, "Time Stamp" },
    { 0x00000014, "Class Name" },
    { 0x00000015, "Stream" },
    { 0x00000016, "Counter" },
    { 0x00000017, "Back Link" },
    { 0x00000018, "Time" },
    { 0x00000019, "Typed Name" },
    { 0x0000001a, "Hold" },
    { 0x0000001b, "Interval" },
    { 0, NULL }
};

static const value_string name_space_type[] = {
    { 0x00000000, "DOS Name Space" },
    { 0x00000001, "MAC Name Space" },
    { 0x00000002, "NFS Name Space" },
    { 0x00000003, "FTAM Name Space" },
    { 0x00000004, "OS/2, Long Name Space" },
    { 0, NULL }
};


static const value_string nds_replica_state[] = {
    { 0x0000, "On" },
    { 0x0001, "New" },
    { 0x0002, "Dying" },
    { 0x0003, "Locked" },
    { 0x0004, "Create Master State 0" },
    { 0x0005, "Create Master State 1" },
    { 0x0006, "Transition On" },
    { 0x0007, "Dead Replica" },
    { 0x0008, "Begin Add" },
    { 0x000b, "Master Start" },
    { 0x000c, "Master Done" },
    { 0x0017, "Federated" },
    { 0x0030, "Split State 0" },
    { 0x0031, "Split State 1" },
    { 0x0040, "Join State 0" },
    { 0x0041, "Join State 1" },
    { 0x0042, "Join State 2" },
    { 0x0050, "Move Subtree State 0" },
    { 0x0051, "Move Subtree State 1" },
    { 0, NULL }
};

static const value_string nds_replica_type[] = {
    { 0x0000, "Master" },
    { 0x0001, "Secondary" },
    { 0x0002, "Read Only" },
    { 0x0003, "Sub Ref" },
    { 0, NULL }
};

static const value_string class_def_type[] = {
    { 0x0000, "Return Class Name" },
    { 0x0001, "Return Class Name, Flag, and Definition" },
    { 0x0002, "Return Class Name, Flag, Definition, and Super Class" },
    { 0x0003, "Return Class Name, Flag, and ASN.1 identifier" },
    { 0x0004, "Return Class Name, Flag, Definition, Super Class, and ACL" },
    { 0x0005, "Return Class Name, Flag, Creation Timestamp, Modification Timestamp, Definition, and ACL" },
    { 0, NULL }
};

static const range_string nds_search_scope[] = {
    { 0x0000, 0x0000, "Examine the base object only" },
    { 0x0001, 0x0001, "Search the immediate subordinates of the base object" },
    { 0x0002, 0x0002, "Search the base object and all its subordinates" },
    { 0x0003, 0x0003, "Search the base objects and all objects in its partition (Implemented in NDS 8)" },
    { 0x0004, 0xFFFF, "No Search Scope Defined" },
    { 0, 0, NULL }
};

static const value_string nds_verb2b_flag_vals[] = {
    { 0, "Request Flags (0x0000) - Retain old object name" },
    { 1, "Request Flags (0x0001) - Delete old object name" },
    { 0,  NULL }
};

static const value_string serv_type_vals[] = {
    { 0, "NetWare" },
    { 1, "OES" },
    { 0,  NULL }
};

static const value_string kernel_type_vals[] = {
    { 0, "NetWare" },
    { 1, "Linux" },
    { 0,  NULL }
};

static int * const ncp_pingflags1[] = {
    &hf_bit1pingflags1,
    &hf_bit2pingflags1,
    &hf_bit3pingflags1,
    &hf_bit4pingflags1,
    &hf_bit5pingflags1,
    &hf_bit6pingflags1,
    &hf_bit7pingflags1,
    &hf_bit8pingflags1,
    &hf_bit9pingflags1,
    &hf_bit10pingflags1,
    &hf_bit11pingflags1,
    &hf_bit12pingflags1,
    &hf_bit13pingflags1,
    &hf_bit14pingflags1,
    &hf_bit15pingflags1,
    &hf_bit16pingflags1,
    NULL
};

static int * const ncp_pingflags2[] = {
    &hf_bit1pingflags2,
    &hf_bit2pingflags2,
    &hf_bit3pingflags2,
    &hf_bit4pingflags2,
    &hf_bit5pingflags2,
    &hf_bit6pingflags2,
    &hf_bit7pingflags2,
    &hf_bit8pingflags2,
    &hf_bit9pingflags2,
    &hf_bit10pingflags2,
    &hf_bit11pingflags2,
    &hf_bit12pingflags2,
    &hf_bit13pingflags2,
    &hf_bit14pingflags2,
    &hf_bit15pingflags2,
    &hf_bit16pingflags2,
    NULL
};

static int * const ncp_pingvflags1[] = {
    &hf_bit1pingvflags1,
    &hf_bit2pingvflags1,
    &hf_bit3pingvflags1,
    &hf_bit4pingvflags1,
    &hf_bit5pingvflags1,
    &hf_bit6pingvflags1,
    &hf_bit7pingvflags1,
    &hf_bit8pingvflags1,
    &hf_bit9pingvflags1,
    &hf_bit10pingvflags1,
    &hf_bit11pingvflags1,
    &hf_bit12pingvflags1,
    &hf_bit13pingvflags1,
    &hf_bit14pingvflags1,
    &hf_bit15pingvflags1,
    &hf_bit16pingvflags1,
    NULL
};

static int * const ncp_pingpflags1[] = {
    &hf_bit1pingpflags1,
    &hf_bit2pingpflags1,
    &hf_bit3pingpflags1,
    &hf_bit4pingpflags1,
    &hf_bit5pingpflags1,
    &hf_bit6pingpflags1,
    &hf_bit7pingpflags1,
    &hf_bit8pingpflags1,
    &hf_bit9pingpflags1,
    &hf_bit10pingpflags1,
    &hf_bit11pingpflags1,
    &hf_bit12pingpflags1,
    &hf_bit13pingpflags1,
    &hf_bit14pingpflags1,
    &hf_bit15pingpflags1,
    &hf_bit16pingpflags1,
    NULL
};

static int * const ndsprotflags[] = {
    &hf_ndsprot1flag,
    &hf_ndsprot2flag,
    &hf_ndsprot3flag,
    &hf_ndsprot4flag,
    &hf_ndsprot5flag,
    &hf_ndsprot6flag,
    &hf_ndsprot7flag,
    &hf_ndsprot8flag,
    &hf_ndsprot9flag,
    &hf_ndsprot10flag,
    &hf_ndsprot11flag,
    &hf_ndsprot12flag,
    &hf_ndsprot13flag,
    &hf_ndsprot14flag,
    &hf_ndsprot15flag,
    &hf_ndsprot16flag,
    NULL
};

static int * const ncp_infoflagsl[] = {
    &hf_bit1infoflagsl,
    &hf_bit2infoflagsl,
    &hf_bit3infoflagsl,
    &hf_bit4infoflagsl,
    &hf_bit5infoflagsl,
    &hf_bit6infoflagsl,
    &hf_bit7infoflagsl,
    &hf_bit8infoflagsl,
    &hf_bit9infoflagsl,
    &hf_bit10infoflagsl,
    &hf_bit11infoflagsl,
    &hf_bit12infoflagsl,
    &hf_bit13infoflagsl,
    &hf_bit14infoflagsl,
    &hf_bit15infoflagsl,
    &hf_bit16infoflagsl,
    NULL
};

static int * const ncp_infoflagsh[] = {
    &hf_bit1infoflagsh,
    &hf_bit2infoflagsh,
    &hf_bit3infoflagsh,
    &hf_bit4infoflagsh,
    &hf_bit5infoflagsh,
    &hf_bit6infoflagsh,
    &hf_bit7infoflagsh,
    &hf_bit8infoflagsh,
    &hf_bit9infoflagsh,
    &hf_bit10infoflagsh,
    &hf_bit11infoflagsh,
    &hf_bit12infoflagsh,
    &hf_bit13infoflagsh,
    &hf_bit14infoflagsh,
    &hf_bit15infoflagsh,
    &hf_bit16infoflagsh,
    NULL
};

static int * const ncp_retinfoflagsh[] = {
    &hf_bit1retinfoflagsh,
    &hf_bit2retinfoflagsh,
    &hf_bit3retinfoflagsh,
    &hf_bit4retinfoflagsh,
    &hf_bit5retinfoflagsh,
    &hf_bit6retinfoflagsh,
    &hf_bit7retinfoflagsh,
    &hf_bit8retinfoflagsh,
    &hf_bit9retinfoflagsh,
    &hf_bit10retinfoflagsh,
    &hf_bit11retinfoflagsh,
    &hf_bit12retinfoflagsh,
    &hf_bit13retinfoflagsh,
    &hf_bit14retinfoflagsh,
    &hf_bit15retinfoflagsh,
    &hf_bit16retinfoflagsh,
    NULL
};

static int * const ncp_acflags[] = {
    &hf_bit1acflags,
    &hf_bit2acflags,
    &hf_bit3acflags,
    &hf_bit4acflags,
    &hf_bit5acflags,
    &hf_bit6acflags,
    &hf_bit7acflags,
    &hf_bit8acflags,
    &hf_bit9acflags,
    &hf_bit10acflags,
    &hf_bit11acflags,
    &hf_bit12acflags,
    &hf_bit13acflags,
    &hf_bit14acflags,
    &hf_bit15acflags,
    &hf_bit16acflags,
    NULL
};

static int * const ncp_eflags[] = {
    &hf_bit1eflags,
    &hf_bit2eflags,
    &hf_bit3eflags,
    &hf_bit4eflags,
    &hf_bit5eflags,
    &hf_bit6eflags,
    &hf_bit7eflags,
    &hf_bit8eflags,
    &hf_bit9eflags,
    &hf_bit10eflags,
    &hf_bit11eflags,
    &hf_bit12eflags,
    &hf_bit13eflags,
    &hf_bit14eflags,
    &hf_bit15eflags,
    &hf_bit16eflags,
    NULL
};

static int * const ncp_cflags[] = {
    &hf_bit1cflags,
    &hf_bit2cflags,
    &hf_bit3cflags,
    &hf_bit4cflags,
    &hf_bit5cflags,
    &hf_bit6cflags,
    &hf_bit7cflags,
    &hf_bit8cflags,
    &hf_bit9cflags,
    &hf_bit10cflags,
    &hf_bit11cflags,
    &hf_bit12cflags,
    &hf_bit13cflags,
    &hf_bit14cflags,
    &hf_bit15cflags,
    &hf_bit16cflags,
    NULL
};

static int * const ncp_lflags[] = {
    &hf_bit1lflags,
    &hf_bit2lflags,
    &hf_bit3lflags,
    &hf_bit4lflags,
    &hf_bit5lflags,
    &hf_bit6lflags,
    &hf_bit7lflags,
    &hf_bit8lflags,
    &hf_bit9lflags,
    &hf_bit10lflags,
    &hf_bit11lflags,
    &hf_bit12lflags,
    &hf_bit13lflags,
    &hf_bit14lflags,
    &hf_bit15lflags,
    &hf_bit16lflags,
    NULL
};

static int * const ncp_nflags[] = {
    &hf_bit1nflags,
    &hf_bit2nflags,
    &hf_bit3nflags,
    &hf_bit4nflags,
    &hf_bit5nflags,
    &hf_bit6nflags,
    &hf_bit7nflags,
    &hf_bit8nflags,
    &hf_bit9nflags,
    &hf_bit10nflags,
    &hf_bit11nflags,
    &hf_bit12nflags,
    &hf_bit13nflags,
    &hf_bit14nflags,
    &hf_bit15nflags,
    &hf_bit16nflags,
    NULL
};

static int * const ncp_rflags[] = {
    &hf_bit1rflags,
    &hf_bit2rflags,
    &hf_bit3rflags,
    &hf_bit4rflags,
    &hf_bit5rflags,
    &hf_bit6rflags,
    &hf_bit7rflags,
    &hf_bit8rflags,
    &hf_bit9rflags,
    &hf_bit10rflags,
    &hf_bit11rflags,
    &hf_bit12rflags,
    &hf_bit13rflags,
    &hf_bit14rflags,
    &hf_bit15rflags,
    &hf_bit16rflags,
    NULL
};

static int * const ncp_outflags[] = {
    &hf_bit1outflags,
    &hf_bit2outflags,
    &hf_bit3outflags,
    &hf_bit4outflags,
    &hf_bit5outflags,
    &hf_bit6outflags,
    &hf_bit7outflags,
    &hf_bit8outflags,
    &hf_bit9outflags,
    &hf_bit10outflags,
    &hf_bit11outflags,
    &hf_bit12outflags,
    &hf_bit13outflags,
    &hf_bit14outflags,
    &hf_bit15outflags,
    &hf_bit16outflags,
    NULL
};

static int * const ncp_siflags[] = {
    &hf_bit1siflags,
    &hf_bit2siflags,
    &hf_bit3siflags,
    &hf_bit4siflags,
    &hf_bit5siflags,
    &hf_bit6siflags,
    &hf_bit7siflags,
    &hf_bit8siflags,
    &hf_bit9siflags,
    &hf_bit10siflags,
    &hf_bit11siflags,
    &hf_bit12siflags,
    &hf_bit13siflags,
    &hf_bit14siflags,
    &hf_bit15siflags,
    &hf_bit16siflags,
    NULL
};

static int * const ncp_vflags[] = {
    &hf_bit1vflags,
    &hf_bit2vflags,
    &hf_bit3vflags,
    &hf_bit4vflags,
    &hf_bit5vflags,
    &hf_bit6vflags,
    &hf_bit7vflags,
    &hf_bit8vflags,
    &hf_bit9vflags,
    &hf_bit10vflags,
    &hf_bit11vflags,
    &hf_bit12vflags,
    &hf_bit13vflags,
    &hf_bit14vflags,
    &hf_bit15vflags,
    &hf_bit16vflags,
    NULL
};

static int * const nds_bitflags[] = {
    &hf_nds_bit1,
    &hf_nds_bit2,
    &hf_nds_bit3,
    &hf_nds_bit4,
    &hf_nds_bit5,
    &hf_nds_bit6,
    &hf_nds_bit7,
    &hf_nds_bit8,
    &hf_nds_bit9,
    &hf_nds_bit10,
    &hf_nds_bit11,
    &hf_nds_bit12,
    &hf_nds_bit13,
    &hf_nds_bit14,
    &hf_nds_bit15,
    &hf_nds_bit16,
    NULL
};

static int * const ncp_l1flagsl[] = {
    &hf_bit1l1flagsl,
    &hf_bit2l1flagsl,
    &hf_bit3l1flagsl,
    &hf_bit4l1flagsl,
    &hf_bit5l1flagsl,
    &hf_bit6l1flagsl,
    &hf_bit7l1flagsl,
    &hf_bit8l1flagsl,
    &hf_bit9l1flagsl,
    &hf_bit10l1flagsl,
    &hf_bit11l1flagsl,
    &hf_bit12l1flagsl,
    &hf_bit13l1flagsl,
    &hf_bit14l1flagsl,
    &hf_bit15l1flagsl,
    &hf_bit16l1flagsl,
    NULL
};

static int * const ncp_l1flagsh[] = {
    &hf_bit1l1flagsh,
    &hf_bit2l1flagsh,
    &hf_bit3l1flagsh,
    &hf_bit4l1flagsh,
    &hf_bit5l1flagsh,
    &hf_bit6l1flagsh,
    &hf_bit7l1flagsh,
    &hf_bit8l1flagsh,
    &hf_bit9l1flagsh,
    &hf_bit10l1flagsh,
    &hf_bit11l1flagsh,
    &hf_bit12l1flagsh,
    &hf_bit13l1flagsh,
    &hf_bit14l1flagsh,
    &hf_bit15l1flagsh,
    &hf_bit16l1flagsh,
    NULL
};

static void
process_ptvc_record(ptvcursor_t *ptvc, packet_info *pinfo, const ptvc_record *rec,
                    bool *req_cond_results, bool really_decode,
                    const ncp_record *ncp_rec, bool request);

/* NCP packets come in request/reply pairs. The request packets tell the type
 * of NCP request and give a sequence ID. The response, unfortunately, only
 * identifies itself via the sequence ID; you have to know what type of NCP
 * request the request packet contained in order to successfully parse the NCP
 * response. A global method for doing this does not exist in wireshark yet
 * (NFS also requires it), so for now the NCP section will keep its own hash
 * table keeping track of NCP packet types.
 *
 * We construct a conversation specified by the client and server
 * addresses and the connection number; the key representing the unique
 * NCP request then is composed of the pointer to the conversation
 * structure, cast to a "uint" (which may throw away the upper 32
 * bits of the pointer on a P64 platform, but the low-order 32 bits
 * are more likely to differ between conversations than the upper 32 bits),
 * and the sequence number.
 *
 * The value stored in the hash table is the ncp_req_hash_value pointer. This
 * struct tells us the NCP type and gives the ncp2222_record pointer, if
 * ncp_type == 0x2222.
 */
typedef struct {
    conversation_t  *conversation;
    uint32_t          nw_sequence_long;
} ncp_req_hash_key;


typedef struct {
    uint32_t         nw_eid;
} ncp_req_eid_hash_key;

/*
 * XXX - should the object_name be a pointer, initialized to null,
 * and set to a wmem-allocated copy of the full string?
 */
typedef struct {
    ncp_req_eid_hash_key    *nds_eid;
    char                    object_name[256];
} ncp_req_eid_hash_value;

static wmem_map_t *ncp_req_hash;
static wmem_map_t *ncp_req_eid_hash;

static uint32_t check_offset_addition(uint32_t offset, uint32_t value, proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
{
    if (offset > UINT32_MAX - value) {
        proto_tree_add_expert_format(tree, pinfo, &ei_ncp_value_too_large, tvb, 0, 0, "Offset value too large: %u", value);
        THROW(ReportedBoundsError);
    }
    return offset + value;
}

/* Hash Functions */
static gboolean
ncp_equal(const void *v, const void *v2)
{
    const ncp_req_hash_key *val1 = (const ncp_req_hash_key*)v;
    const ncp_req_hash_key *val2 = (const ncp_req_hash_key*)v2;

    if (val1->conversation == val2->conversation &&
        val1->nw_sequence_long  == val2->nw_sequence_long ) {
        return TRUE;
    }
    return FALSE;
}

static gboolean
ncp_eid_equal(const void *v, const void *v2)
{
    const ncp_req_eid_hash_key *val1 = (const ncp_req_eid_hash_key*)v;
    const ncp_req_eid_hash_key *val2 = (const ncp_req_eid_hash_key*)v2;

    if (val1->nw_eid == val2->nw_eid ) {
        return TRUE;
    }
    return FALSE;
}

static unsigned
ncp_hash(const void *v)
{
    const ncp_req_hash_key *ncp_key = (const ncp_req_hash_key*)v;
    return GPOINTER_TO_UINT(ncp_key->conversation) + ncp_key->nw_sequence_long;
}

static unsigned
ncp_eid_hash(const void *v)
{
    const ncp_req_eid_hash_key *ncp_eid_key = (const ncp_req_eid_hash_key*)v;
    return GPOINTER_TO_UINT(ncp_eid_key->nw_eid);
}

static void
ncp_init_protocol(void)
{
    int i;

    for (i = 0; i < 99; i++) {
        frags[i].nds_frag = 0xfffffff0;
    }
}

/* NCP sequence numbers are from 0 - 255. After reaching 255 the
 * sequence number wraps back to 0. Change nw_sequence to nw_sequence_long
 * and use upper bits to make sequence numbers unique. This way
 * future attempts to locate initiating packet will succeed.
 */
static ncp_req_hash_value*
ncp_hash_insert(conversation_t *conversation, uint8_t nw_sequence,
                const ncp_record *ncp_rec, uint32_t pkt_num)
{
    ncp_req_hash_key    *request_key;
    ncp_req_hash_value  *request_value;

    /* Now remember the request, so we can find it if we later
       a reply to it. */
    request_key = wmem_new(wmem_file_scope(), ncp_req_hash_key);
    request_key->conversation = conversation;
    /* Make sequence number unique */
    request_key->nw_sequence_long = (0x10000 + ((pkt_num/16)<<16)) | nw_sequence;

    request_value = wmem_new0(wmem_file_scope(), ncp_req_hash_value);
    request_value->ncp_rec = ncp_rec;
    request_value->req_cond_results = NULL;
    request_value->req_nds_flags = 0;
    request_value->nds_request_verb = 0;
    request_value->nds_version = 0;
    (void) g_strlcpy(request_value->object_name, "", 256);
    request_value->nds_frag = true;

    wmem_map_insert(ncp_req_hash, request_key, request_value);

    return request_value;
}

static ncp_req_eid_hash_value*
ncp_eid_hash_insert(uint32_t nw_eid)
{
    ncp_req_eid_hash_key    *request_eid_key;
    ncp_req_eid_hash_value  *request_eid_value;

    /* Now remember the request, so we can find it if we later
       a reply to it. */
    request_eid_key = wmem_new(wmem_file_scope(), ncp_req_eid_hash_key);
    request_eid_key->nw_eid = nw_eid;

    request_eid_value = wmem_new0(wmem_file_scope(), ncp_req_eid_hash_value);
    (void) g_strlcpy(request_eid_value->object_name, "", 256);

    wmem_map_insert(ncp_req_eid_hash, request_eid_key, request_eid_value);

    return request_eid_value;
}

/* Returns the ncp_rec*, or NULL if not found. */
static ncp_req_hash_value*
ncp_hash_lookup(conversation_t *conversation, uint8_t nw_sequence, uint32_t pkt_num)
{
    ncp_req_hash_key  request_key;
    ncp_req_hash_value *temp_value;

    request_key.conversation = conversation;
    /* Find unique sequence number */
    request_key.nw_sequence_long = (0x10000+((pkt_num/16)<<16)) | nw_sequence;

    /* Since masking of sequence number utilizes the packet number as
     * part of it's algorythm it is possible for a packet to sit right
     * on the boundary and fail. (depending on number of packets in trace)
     * Loop through all the previous sequence numbers in the hash to see
     * if the original request packet can be found.
     */
    temp_value = (ncp_req_hash_value *)wmem_map_lookup(ncp_req_hash, &request_key);
    while(!temp_value)
    {
       request_key.nw_sequence_long = request_key.nw_sequence_long-0x10000;
       if((request_key.nw_sequence_long & 0xffff0000) == 0){
            break;
       }
       temp_value = (ncp_req_hash_value *)wmem_map_lookup(ncp_req_hash, &request_key);
    }
    return temp_value;
}

/* Returns the value_rec* for needed EID, or NULL if not found. */
static ncp_req_eid_hash_value*
ncp_eid_hash_lookup(conversation_t *conversation _U_, uint32_t nw_eid)
{
    ncp_req_eid_hash_key  request_eid_key;

    request_eid_key.nw_eid = nw_eid;

    return (ncp_req_eid_hash_value *)wmem_map_lookup(ncp_req_eid_hash, &request_eid_key);
}

/* Does NCP func require a subfunction code? */
static bool
ncp_requires_subfunc(uint8_t func)
{
    const uint8_t *ncp_func_requirement = ncp_func_requires_subfunc;

    while (*ncp_func_requirement != 0) {
        if (*ncp_func_requirement == func) {
            return true;
        }
        ncp_func_requirement++;
    }
    return false;
}

/* Does the NCP func have a length parameter? */
static bool
ncp_has_length_parameter(uint8_t func)
{
    const uint8_t *ncp_func_requirement = ncp_func_has_no_length_parameter;

    while (*ncp_func_requirement != 0) {
        if (*ncp_func_requirement == func) {
            return false;
        }
        ncp_func_requirement++;
    }
    return true;
}


/* Return a ncp_record* based on func and possibly subfunc */
static const ncp_record *
ncp_record_find(uint8_t func, uint8_t subfunc)
{
    const ncp_record *ncp_rec = ncp_packets;

    while(ncp_rec->func != 0 || ncp_rec->subfunc != 0 ||
          ncp_rec->name != NULL ) {
        if (ncp_rec->func == func) {
            if (ncp_rec->has_subfunc) {
                if (ncp_rec->subfunc == subfunc) {
                    return ncp_rec;
                }
            }
            else {
                return ncp_rec;
            }
        }
        ncp_rec++;
    }
    return NULL;
}

#define NW_UNI_MAX 1024

#define VTYPE_NONE                       0  /* no value */
#define VTYPE_UINT8                      1
#define VTYPE_UINT16                     2
#define VTYPE_UINT32                     3
#define VTYPE_STRING                     4
#define VTYPE_BITFIELD                   5
#define VTYPE_MULTIVALUE_UINT32          6
#define VTYPE_BYTES                      7
#define VTYPE_BOOLEAN                    8
#define VTYPE_ITEM                       9

#define MVTYPE_ATTR_REQUEST              1
#define MVTYPE_ATTR_REPLY                2
#define MVTYPE_ATTR_REQUEST2             3
#define MVTYPE_READ_CLASS_REQ            4
#define MVTYPE_READ_REPLICAS             5
#define MVTYPE_MODIFY_ATTR_REQUEST       6
#define MVTYPE_ADDR_REFERRAL_REQUEST     7
#define MVTYPE_ADDR_REFERRAL_REPLY       8
#define MVTYPE_LOC_ADDR_REFERRAL_REPLY   9
#define MVTYPE_PROC_ENTRY_SPECIFIERS    10
#define MVTYPE_PRINT_TIMESTAMP          11
#define MVTYPE_LIST_PARTITIONS          12
#define MVTYPE_CLASS_NAMES              13
#define MVTYPE_MODIFY_CLASS             14
#define MVTYPE_ADD_ATTR_REQUEST         15
#define MVTYPE_PROCESS_TAGS             16
#define MVTYPE_PROCESS_ITERATOR         17

typedef struct {
    uint8_t         vtype;
    uint32_t        vvalue;
    const char*     vstring;
    const char*     vdesc;
    uint32_t        vlength;
    uint32_t        voffset;
    uint32_t        hfname;
    const char*     bit1;
    uint32_t        bit1hfname;
    const char*     bit2;
    uint32_t        bit2hfname;
    const char*     bit3;
    uint32_t        bit3hfname;
    const char*     bit4;
    uint32_t        bit4hfname;
    const char*     bit5;
    uint32_t        bit5hfname;
    const char*     bit6;
    uint32_t        bit6hfname;
    const char*     bit7;
    uint32_t        bit7hfname;
    const char*     bit8;
    uint32_t        bit8hfname;
    const char*     bit9;
    uint32_t        bit9hfname;
    const char*     bit10;
    uint32_t        bit10hfname;
    const char*     bit11;
    uint32_t        bit11hfname;
    const char*     bit12;
    uint32_t        bit12hfname;
    const char*     bit13;
    uint32_t        bit13hfname;
    const char*     bit14;
    uint32_t        bit14hfname;
    const char*     bit15;
    uint32_t        bit15hfname;
    const char*     bit16;
    uint32_t        bit16hfname;
    uint8_t         mvtype;
    uint32_t        vflags;
    uint32_t        nds_version;
    uint32_t        pflags; /* NDS Protocol Flags */
} nds_val;

static proto_item*
add_ptvc_field(packet_info* pinfo, ptvcursor_t *ptvc, const ptvc_record *rec, bool request, bool repeat, unsigned* ret_value)
{
    header_field_info* hinfo = proto_registrar_get_nth(*rec->hf_ptr);

    if (!repeat && request && rec->req_info_str)
        col_set_str(pinfo->cinfo, COL_INFO, "C ");

    /* We may want integer values regardless of whether or not the value is displayed in INFO column */
    if (FT_IS_UINT(hinfo->type) || FT_IS_INT(hinfo->type)) {
        uint32_t value32 = 0;
        uint64_t value64 = 0;

        switch(rec->length)
        {
        case 1:
            value32 = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
            *ret_value = value32;
            break;
        case 2:
            value32 = tvb_get_uint16(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
            *ret_value = value32;
            break;
        case 3:
            value32 = tvb_get_uint24(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
            *ret_value = value32;
            break;
        case 4:
            value32 = tvb_get_uint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
            *ret_value = value32;
            break;
        case 5:
            value64 = tvb_get_uint40(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
            break;
        case 6:
            value64 = tvb_get_uint48(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
            break;
        case 7:
            value64 = tvb_get_uint56(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
            break;
        case 8:
            value64 = tvb_get_uint64(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
            break;
        default:
            DISSECTOR_ASSERT(false);
            break;
        }

        if (request && rec->req_info_str) {
            if (rec->length <= 4) {
                col_append_fstr(pinfo->cinfo, COL_INFO,
                        (const char*)(repeat ? rec->req_info_str->repeat_string : rec->req_info_str->first_string),
                        value32);
            } else {
                col_append_fstr(pinfo->cinfo, COL_INFO,
                        (const char*)(repeat ? rec->req_info_str->repeat_string : rec->req_info_str->first_string),
                        value64);

            }
        }
    } else if (request && rec->req_info_str) {
        if (hinfo->type == FT_STRING) {
            col_append_fstr(pinfo->cinfo, COL_INFO,
                                (const char*)(repeat ? rec->req_info_str->repeat_string : rec->req_info_str->first_string),
                                 tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                     ptvcursor_current_offset(ptvc), rec->length, ENC_ASCII));
        } else if (hinfo->type == FT_STRINGZ) {
            int length;
            col_append_fstr(pinfo->cinfo, COL_INFO,
                                (const char*)(repeat ? rec->req_info_str->repeat_string : rec->req_info_str->first_string),
                                tvb_get_stringz_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                    ptvcursor_current_offset(ptvc), &length, ENC_ASCII));
        } else if (hinfo->type == FT_UINT_STRING) {
            uint32_t length = 0;

            switch(rec->length)
            {
            case 1:
                length = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                break;
            case 2:
                length = tvb_get_uint16(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
                break;
            case 3:
                length = tvb_get_uint24(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
                break;
            case 4:
                length = tvb_get_uint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), rec->endianness);
                break;
            default:
                DISSECTOR_ASSERT(false);
                break;
            }

            col_append_fstr(pinfo->cinfo, COL_INFO,
                                (const char*)(repeat ? rec->req_info_str->repeat_string : rec->req_info_str->first_string),
                                tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                    ptvcursor_current_offset(ptvc)+rec->length, length, ENC_ASCII));
        } else if (hinfo->type == FT_BYTES) {
            col_append_fstr(pinfo->cinfo, COL_INFO,
                                (const char*)(repeat ? rec->req_info_str->repeat_string : rec->req_info_str->first_string),
                                tvb_bytes_to_str(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                    ptvcursor_current_offset(ptvc), rec->length));
        }
    }

    return ptvcursor_add(ptvc, *rec->hf_ptr,
                      rec->length,
                      rec->endianness);
}

/*
 * XXX - are these just DOS-format dates and times?
 *
 * Should we put code to understand various date and time formats (UNIX,
 * DOS, SMB weird mutant UNIX, NT, Mac, etc. into libwireshark, and have
 * the "display" member of an HF_ABSOLUTE_TIME field specify whether
 * it's DOS date/DOS time, DOS time/DOS date, NT time, UNIX time_t,
 * UNIX "struct timeval", NFSv3/NFSv4 seconds/nanoseconds, Mac, etc.?
 *
 * What about hijacking the "bitmask" field to specify the precision of
 * the time stamp, or putting a combination of precision and format
 * into the "display" member?
 *
 * What about relative times?  Should they have units (seconds, milliseconds,
 * microseconds, nanoseconds, etc.), precision, and format in there?
 */
static void
padd_date( char *result, uint32_t date_value )
{
    snprintf(result, ITEM_LABEL_LENGTH, "%04u/%02u/%02u",
                ((date_value & 0xfe00) >> 9) + 1980,
                (date_value & 0x01e0) >> 5,
                date_value & 0x001f);
}

static void
padd_time( char *result, uint32_t time_value )
{
    snprintf(result, ITEM_LABEL_LENGTH, "%02u:%02u:%02u",
                ((time_value & 0xf800) >> 11),
                ((time_value & 0x07e0) >> 5),
                (time_value & 0x001f) * 2);
}

/* Add a value for a ptvc_record, and process the sub-ptvc_record
 * that it points to. */
static void
process_bitfield_sub_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec,
                                 bool really_decode)
{
    proto_item          *item;
    proto_tree          *sub_tree;
    const ptvc_record   *sub_rec;
    int                 current_offset;
    int                 ett;
    ptvcursor_t         *sub_ptvc;

    if (really_decode) {
        /* Save the current offset */
        current_offset = ptvcursor_current_offset(ptvc);

        /* Add the item */
        item = ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
                             rec->endianness);

        ett = *rec->sub_ptvc_rec->ett;

        /* Make a new protocol sub-tree */
        sub_tree = proto_item_add_subtree(item, ett);

        /* Make a new ptvcursor */
        sub_ptvc = ptvcursor_new(wmem_packet_scope(), sub_tree, ptvcursor_tvbuff(ptvc),
                                 current_offset);

        /* Use it */
        sub_rec = rec->sub_ptvc_rec->ptvc_rec;
        while(sub_rec->hf_ptr != NULL) {
            DISSECTOR_ASSERT(!sub_rec->sub_ptvc_rec);
            ptvcursor_add_no_advance(sub_ptvc, *sub_rec->hf_ptr,
                                     sub_rec->length,
                                     sub_rec->endianness);
            sub_rec++;
        }

        /* Free it. */
        ptvcursor_free(sub_ptvc);
    }
    else {
        DISSECTOR_ASSERT(rec->length > 0 &&
                         proto_registrar_get_nth(*rec->hf_ptr)->type != FT_UINT_STRING);
        ptvcursor_advance(ptvc, rec->length);
    }
}

/* Process a sub-ptvc_record that points to a "struct" ptvc_record. */
static void
process_struct_sub_ptvc_record(ptvcursor_t *ptvc, packet_info *pinfo, const ptvc_record *rec,
                               bool *req_cond_results, bool really_decode,
                               const ncp_record *ncp_rec, bool request)
{
    const ptvc_record   *sub_rec;
    int                 ett;
    proto_tree          *old_tree=NULL, *new_tree;
    proto_item          *item=NULL;
    int                 offset=0;

    /* Create a sub-proto_tree? */
    if (rec->sub_ptvc_rec->descr) {
        ett = *rec->sub_ptvc_rec->ett;
        old_tree = ptvcursor_tree(ptvc);
        offset = ptvcursor_current_offset(ptvc);
        new_tree = proto_tree_add_subtree(old_tree, ptvcursor_tvbuff(ptvc), offset, -1,
                                          ett, &item, rec->sub_ptvc_rec->descr);
        ptvcursor_set_tree(ptvc, new_tree);
    }

    /* Get the ptvc_record for the struct and call our caller
     * to process it. */
    sub_rec = rec->sub_ptvc_rec->ptvc_rec;
    process_ptvc_record(ptvc, pinfo, sub_rec, req_cond_results, really_decode, ncp_rec, request);

    /* Re-set the tree */
    if (rec->sub_ptvc_rec->descr) {
        if (ptvcursor_current_offset(ptvc) <= offset)
            THROW(ReportedBoundsError);

        proto_item_set_len(item, ptvcursor_current_offset(ptvc) - offset);
        ptvcursor_set_tree(ptvc, old_tree);
    }
}

/* Run through the table of ptvc_record's and add info to the tree. This
 * is the work-horse of process_ptvc_record(). */
static void
_process_ptvc_record(ptvcursor_t *ptvc, packet_info *pinfo, const ptvc_record *rec,
                     bool *req_cond_results, bool really_decode,
                     const ncp_record *ncp_rec, bool request)
{
    unsigned    i, repeat_count, repeat_value;

    if (rec->sub_ptvc_rec) {
        /* Repeat this? */
        if (rec->repeat_index >= NO_REPEAT) {
            if (rec->hf_ptr == PTVC_STRUCT) {
                process_struct_sub_ptvc_record(ptvc, pinfo, rec,
                                               req_cond_results, really_decode,
                                               ncp_rec, request);
            }
            else {
                process_bitfield_sub_ptvc_record(ptvc, rec,
                                                 really_decode);
            }
        }
        else {
            repeat_count = repeat_vars[rec->repeat_index];
            for (i = 0; i < repeat_count; i++ ) {
                if (rec->hf_ptr == PTVC_STRUCT) {
                    process_struct_sub_ptvc_record(ptvc, pinfo, rec,
                                                   req_cond_results, really_decode,
                                                   ncp_rec, request);
                }
                else {
                    process_bitfield_sub_ptvc_record(ptvc, rec,
                                                     really_decode);
                }
            }
        }
    }
    else {
        /* If we can't repeat this field, we might use it
         * to set a 'var'. */
        if (rec->repeat_index == NO_REPEAT) {
            if (really_decode) {
                repeat_value = 0;
                add_ptvc_field(pinfo, ptvc, rec, request, false, &repeat_value);

                /* Set the value as a 'var' ? */
                if (rec->var_index != NO_VAR) {
                    repeat_vars[rec->var_index] = repeat_value;
                }
            }
            else {
                /* If we don't decode the field, we
                 * better not use the value to set a var.
                 * Actually, we could, as long as we don't
                 * *use* that var; for now keep this assert in
                 * place. */
                DISSECTOR_ASSERT(rec->var_index == NO_VAR);

                /* This had better not be variable-length,
                 * either. */
                DISSECTOR_ASSERT(rec->length > 0 &&
                                 proto_registrar_get_nth(*rec->hf_ptr)->type != FT_UINT_STRING);
                ptvcursor_advance(ptvc, rec->length);
            }
        }
        else {
            /* We do repeat this field. */
            repeat_count = repeat_vars[rec->repeat_index];
            if (really_decode) {
                for (i = 0; i < repeat_count; i++ ) {
                    add_ptvc_field(pinfo, ptvc, rec, request, i != 0, &repeat_value);
                }
            }
            else {
                for (i = 0; i < repeat_count; i++ ) {
                    DISSECTOR_ASSERT(rec->length > 0 &&
                                     proto_registrar_get_nth(*rec->hf_ptr)->type != FT_UINT_STRING);
                    ptvcursor_advance(ptvc, rec->length);
                }
            }
        }
    }
}

/* Run through the table of ptvc_record's and add info to the tree.
 * Honor a request condition result. */
static void
process_ptvc_record(ptvcursor_t *ptvc, packet_info *pinfo, const ptvc_record *rec,
                    bool *req_cond_results, bool really_decode,
                    const ncp_record *ncp_rec, bool request)
{
    bool decode;
    ptvcursor_t *expert_ptvc;
    proto_tree* expert_tree = ptvcursor_tree(ptvc);
    tvbuff_t* expert_tvb = ptvcursor_tvbuff(ptvc);
    int expert_offset = ptvcursor_current_offset(ptvc);

    while(rec->hf_ptr != NULL) {
        decode = really_decode;
        /* If we're supposed to decode, check the request condition
         * results to see if we should override this and *not* decode. */
        if (decode && req_cond_results) {
            if (rec->req_cond_index != NO_REQ_COND) {
                if (req_cond_results[rec->req_cond_index] == false) {
                    decode = false;
                }
            }
        }
        if (decode || ncp_rec->req_cond_size_type == REQ_COND_SIZE_CONSTANT) {
            _process_ptvc_record(ptvc, pinfo, rec, req_cond_results, decode, ncp_rec, request);
        }
        rec++;
    }

    /* Collect any potential expert info that would have been collected over
       these records */
    if (ncp_rec->expert_handler_func)
    {
        expert_ptvc = ptvcursor_new(pinfo->pool, expert_tree, expert_tvb, expert_offset);
        ncp_rec->expert_handler_func(expert_ptvc, pinfo, ncp_rec, request);
        ptvcursor_free(expert_ptvc);
    }
}



/* Clear the repeat_vars array. */
static void
clear_repeat_vars(void)
{
    unsigned i;

    for (i = 0 ; i < NUM_REPEAT_VARS; i++ ) {
        repeat_vars[i] = 0;
    }
}


/* Given an error_equivalency table and a completion code, return
 * the string representing the error. */
static const char*
ncp_error_string(const error_equivalency *errors, uint8_t completion_code)
{

    while (errors->ncp_error_index != -1) {
        if (errors->error_in_packet == completion_code) {
            return ncp_errors[errors->ncp_error_index];
        }
        errors++;
    }

    return "Unknown Error Code";
}

static const ncp_record ncp1111_request =
{ 0x1, 0x00, NO_SUBFUNC, "Create Connection Service", NCP_GROUP_CONNECTION,
  NULL, NULL, ncp_0x2_errors, NULL, NO_REQ_COND_SIZE, NULL };

static const ncp_record ncp5555_request =
{ 0x5, 0x00, NO_SUBFUNC, "Destroy Connection Service", NCP_GROUP_CONNECTION,
  NULL, NULL, ncp_0x2_errors, NULL, NO_REQ_COND_SIZE, NULL };

static const ncp_record ncpbbbb_request =
{ 0xb, 0x00, NO_SUBFUNC, "Server Broadcast Message", NCP_GROUP_CONNECTION,
  NULL, NULL, ncp_0x2_errors, NULL, NO_REQ_COND_SIZE, NULL };

static const ncp_record ncplip_echo =
{ 0x1f, 0x00, NO_SUBFUNC, "LIP Echo Packet", NCP_GROUP_CONNECTION,
  NULL, NULL, ncp_0x2_errors, NULL, NO_REQ_COND_SIZE, NULL };

/* Wrapper around proto_tree_free() */
static void free_proto_tree(void *tree)
{
    if (tree) {
        proto_tree_free((proto_tree*) tree);
    }
}

static uint32_t
align_4(tvbuff_t *tvb, uint32_t aoffset)
{
    if(tvb_captured_length_remaining(tvb, aoffset) > 4 )
    {
        return (aoffset%4);
    }
    return 0;
}

/*
 * XXX - should we just use regular string functions, or proto_item_
 * functions, with ENC_UTF_16|ENC_LITTLE_ENDIAN (or ENC_UCS_2, if
 * they don't support full UTF-16)?
 */
static const char *
get_string(tvbuff_t* tvb, unsigned offset, unsigned str_length)
{
    char *dest_buf;
    int i;
    uint16_t c_char;
    int length_remaining = 0;
    int max_length = (str_length < NW_UNI_MAX) ? str_length : NW_UNI_MAX;

    length_remaining = tvb_captured_length_remaining(tvb, offset);
    if((int)str_length > length_remaining)
    {
        THROW(ReportedBoundsError);
    }

    if(str_length == 0)
    {
        return "";
    }

    dest_buf = (char *)wmem_alloc(wmem_packet_scope(), max_length + 1);
    dest_buf[0] = '\0';

    for ( i = 0; i < (int)str_length; i++ )
    {
        c_char = tvb_get_uint8(tvb, offset );
        if (c_char<0x20 || c_char>0x7e)
        {
            if (c_char != 0x00)
            {
                c_char = '.';
                dest_buf[i] = c_char & 0xff;
            }
            else
            {
                i--;
                str_length--;
            }
        }
        else
        {
            dest_buf[i] = c_char & 0xff;
        }
        offset++;
        length_remaining--;

        if(length_remaining==1)
        {
            dest_buf[i+1] = '\0';
            return dest_buf;
        }
        if (i >= 1023) { /* Don't process beyond the size of our variable */
            break;       /* If string is too long just return the first 1K. */
        }
    }
    if (i < 0) {
        i = 0;
    }
    dest_buf[i] = '\0';
    return dest_buf;
}

/* Echo the NDS EID and name for NCP 22,51 replies to expert tap */
static void ncp1633_reply_expert_func(ptvcursor_t *ptvc, packet_info *pinfo, const ncp_record *ncp_rec _U_, bool request)
{
    if (nds_echo_eid && !request) {
        uint32_t object_id;
        uint8_t volume_name_len;
        uint8_t*  volume_name;

        object_id = tvb_get_letohl(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)+126);
        ptvcursor_advance(ptvc, 134);
        volume_name_len = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 1);
        volume_name = tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                ptvcursor_current_offset(ptvc), volume_name_len, ENC_ASCII);

        expert_add_info_format(pinfo, NULL, &ei_ncp_eid,
                                    "EID (%08x) = %s", object_id, volume_name);
    }
}

/* The following allows for specific NCP server info to be echoed to the expert tap. */
static void ncp1711_reply_expert_func(ptvcursor_t *ptvc, packet_info *pinfo, const ncp_record *ncp_rec _U_, bool request)
{
    if (ncp_echo_server && !request) {
        uint8_t* fsname;
        uint8_t maj_ver, min_ver, os_lang, serv_type, kernel;
        uint16_t prod_rev;

        fsname = tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                ptvcursor_current_offset(ptvc), 48, ENC_ASCII);
        ptvcursor_advance(ptvc, 48);
        maj_ver = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 1);
        min_ver = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 25); /* Skip unimportant fields */
        prod_rev = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 2);
        os_lang = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 2);
        serv_type = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 1);
        kernel = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 1);

        expert_add_info_format(pinfo, NULL, &ei_ncp_server, "Server %s, version %d.%d, support pack %d, language %d, server type %s, kernel %s", fsname,
                                maj_ver, min_ver, prod_rev, os_lang, val_to_str(serv_type & 0x01, serv_type_vals, "Unknown: %d"),
                                val_to_str(kernel & 0x01, kernel_type_vals, "Unknown: %d") );
    }
}

/* The following allows for Update file handle rights echoed to expert tap. */
static void ncp42_request_expert_func(ptvcursor_t *ptvc, packet_info *pinfo, const ncp_record *ncp_rec _U_, bool request)
{
    if (ncp_echo_file && request) {
        char* filehandle = tvb_bytes_to_str(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                                ptvcursor_current_offset(ptvc)+1, 6);

        expert_add_info_format(pinfo, NULL, &ei_ncp_file_handle, "Close file handle %s", filehandle);
    }
}

/* The following allows for oplock level 1 file opens echoed to expert tap. */
static void file_rights_expert_func(ptvcursor_t *ptvc, packet_info *pinfo, const ncp_record *ncp_rec, bool request)
{
    if (ncp_echo_file) {
        if (request) {
            uint8_t oaction = 0, path_count = 0;
            uint16_t rights = 0;
            uint8_t* filename = "";

            if (ncp_rec->func == 87) {
                switch(ncp_rec->subfunc)
                {
                case 1:
                case 32:
                    oaction = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)+1);
                    ptvcursor_advance(ptvc, 12);
                    rights = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 8);
                    path_count = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 1);
                    filename = tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                ptvcursor_current_offset(ptvc), path_count, ENC_ASCII);
                    break;
                case 33:
                case 30:
                    oaction = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)+2);
                    ptvcursor_advance(ptvc, 16);
                    rights = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 8);
                    path_count = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 1);
                    filename = tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                    ptvcursor_current_offset(ptvc), path_count, ENC_ASCII);
                    break;
                }
            } else if (ncp_rec->func == 89) {
                switch(ncp_rec->subfunc)
                {
                case 1:
                case 32:
                    oaction = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)+1);
                    ptvcursor_advance(ptvc, 12);
                    rights = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 14);
                    path_count = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 1);
                    filename = tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                    ptvcursor_current_offset(ptvc), path_count, ENC_ASCII);
                    break;
                case 33:
                case 30:
                    oaction = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)+2);
                    ptvcursor_advance(ptvc, 16);
                    rights = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 14);
                    path_count = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    ptvcursor_advance(ptvc, 1);
                    filename = tvb_get_string_enc(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                    ptvcursor_current_offset(ptvc), path_count, ENC_ASCII);
                    break;
                }
            }

            expert_add_info_format(pinfo, NULL, &ei_ncp_file_rights,
                                "Op-lock open, mode %s for filename %s with rights %s",
                                val_to_str(oaction & 0xeb, open_create_mode_vals, "Unknown: %d"),
                                filename,
                                val_to_str(rights & 0x5f, ncp_rights_vals, "Unknown: %d"));
        } else {
            if ((ncp_rec->func == 89 || ncp_rec->func == 87) && (ncp_rec->subfunc == 32 || ncp_rec->subfunc == 1)) {
                uint8_t oaction, oplockflg;
                char* filehandle;

                filehandle = tvb_bytes_to_str(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                                ptvcursor_current_offset(ptvc), 4);
                ptvcursor_advance(ptvc, 4);
                oaction = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));

                if (ncp_rec->subfunc == 1) {
                    expert_add_info_format(pinfo, NULL, &ei_ncp_file_handle, "%s - File handle %s",
                                           val_to_str(oaction & 0x8f, open_create_action_vals, "Unknown: %d"),
                                           filehandle);
                }
                else
                {
                    ptvcursor_advance(ptvc, 1);
                    oplockflg = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
                    expert_add_info_format(pinfo, NULL, &ei_ncp_file_handle, "%s - File handle %s, %s",
                                           val_to_str(oaction & 0x8f, open_create_action_vals, "Unknown: %d"),
                                           filehandle,
                                           val_to_str(oplockflg, ncp_o_c_ret_flags_vals, "Unknown: %d"));
                }
            }
        }
    }
}

/* The following allows for oplock ack's and level 2 request echoed to expert tap. */
static void ncp5722_request_expert_func(ptvcursor_t *ptvc, packet_info *pinfo, const ncp_record *ncp_rec _U_, bool request)
{
    if (ncp_echo_file && request) {
        uint32_t filehandle;
        uint8_t cc_function;

        filehandle = tvb_get_ntohl(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
        ptvcursor_advance(ptvc, 4);
        cc_function = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));

        expert_add_info_format(pinfo, NULL, &ei_ncp_op_lock_handle, "Op-lock on handle %08x - %s", filehandle,
                                val_to_str(cc_function, ncp_cc_function_vals, "Unknown: %d"));
    }
}

/* The following allows for Update file handle rights echoed to expert tap. */
static void ncp572c_expert_func(ptvcursor_t *ptvc, packet_info *pinfo, const ncp_record *ncp_rec _U_, bool request)
{
    if (ncp_echo_file) {
        char* filehandle;

        if (request) {
            uint16_t access_rights, new_rights;

            access_rights = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)+8);
            ptvcursor_advance(ptvc, 10);
            new_rights = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
            ptvcursor_advance(ptvc, 2);
            filehandle = tvb_bytes_to_str(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                                    ptvcursor_current_offset(ptvc), 4);

            expert_add_info_format(pinfo, NULL, &ei_ncp_file_rights_change, "Change handle %s rights from:(%s) to:(%s)",
                                   filehandle,
                                   val_to_str(access_rights & 0x1ff, access_rights_vals, "Unknown: %d"),
                                   val_to_str(new_rights & 0x1ff, access_rights_vals, "Unknown: %d"));

        } else {
            uint32_t rights;

            filehandle = tvb_bytes_to_str(pinfo->pool, ptvcursor_tvbuff(ptvc),
                                                    ptvcursor_current_offset(ptvc), 4);
            ptvcursor_advance(ptvc, 4);
            rights = tvb_get_ntohl(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)+8);

            expert_add_info_format(pinfo, NULL, &ei_ncp_effective_rights, "Handle %s effective rights:(%s)", filehandle,
                                    val_to_str(rights & 0x1ff, access_rights_vals, "Unknown: %d"));
        }
    }
}

static void
print_nds_values(proto_tree *vtree, packet_info* pinfo, tvbuff_t *tvb, uint32_t syntax_type, nds_val *vvalues)
{
    uint32_t        value1 = 0;
    uint32_t        value2 = 0;
    uint32_t        value3 = 0;
    uint32_t        value4 = 0;
    uint32_t        value5 = 0;
    uint32_t        voffset = 0, oldvoffset;
    uint32_t        icounter;
    uint32_t        number_of_values = 0;
    uint32_t        number_of_items = 0;
    uint32_t        r;
    proto_item      *vitem;
    proto_tree      *nvtree;
    proto_item      *aditem;
    proto_tree      *adtree;
    const char      *valuestr = NULL;
    int             length_remaining;
    nstime_t        ns;
    bool            entry_rights = false;

    voffset = vvalues->voffset;
#if 0
    if(tvb_get_uint8(tvb, voffset) == 0x00)
    {
        voffset = voffset+2;
    }
#endif

    number_of_values = tvb_get_letohl(tvb, voffset);

    vitem = proto_tree_add_uint_format(vtree, hf_nds_uint32value, tvb, voffset,
                                       4, number_of_values, "Number of Values: %u", number_of_values);

    nvtree = proto_item_add_subtree(vitem, ett_nds);

    oldvoffset = voffset;
    voffset = voffset + 4;

    for (icounter = 1 ; icounter <= number_of_values; icounter++ )
    {
        if (oldvoffset >= voffset) {
            proto_tree_add_expert_format(nvtree, pinfo, &ei_ncp_invalid_offset, tvb, 0, 0, "Invalid offset: %u", voffset);
            THROW(ReportedBoundsError);
        }
        oldvoffset = voffset;
        switch(syntax_type)
        {
        case 0x00000006:        /* Case Insensitive List */
        case 0x00000012:        /* Postal Address */
            voffset += align_4(tvb, voffset);
            voffset = voffset+4;
            number_of_items = tvb_get_letohl(tvb, voffset);
            voffset = voffset+4;
            for (r=1; r<=number_of_items; r++)
            {
                value1 = tvb_get_letohl(tvb, voffset);
                voffset = voffset + 4;
                vvalues->vstring = get_string(tvb, voffset, value1);
                proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                      value1, vvalues->vstring);
                voffset = check_offset_addition(voffset, value1, nvtree, pinfo, tvb);
                voffset += align_4(tvb, voffset);
            }
            break;
        case 0x00000007:        /* Boolean */
            voffset+=4;                            /* this is always just a parameter count of 1, so ignore */
            value1 = tvb_get_uint8(tvb, voffset); /* Boolean value */
            if (value1==0)
            {
                vvalues->vstring = "False";
            }
            else
            {
                vvalues->vstring = "True";
            }
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  1, vvalues->vstring);
            voffset=voffset+1;
            voffset += align_4(tvb, voffset);
            break;
        case 0x00000009:        /* Binary String */
            value1 = tvb_get_letohl(tvb, voffset); /* length of field */
            length_remaining = tvb_captured_length_remaining(tvb, voffset);
            if(length_remaining == -1 || value1 > (uint32_t) length_remaining)
            {
                break;
            }
            voffset += 4;
            proto_tree_add_item(nvtree, hf_value_bytes, tvb, voffset, value1, ENC_NA);
            voffset += value1;
            voffset += (value1%2);
            break;
        case 0x0000000d:        /* Binary String List */
            value1 = tvb_get_letohl(tvb, voffset); /* Overall length of field list */
            length_remaining = tvb_captured_length_remaining(tvb, voffset);
            if(length_remaining == -1 || value1 > (uint32_t) length_remaining)
            {
                break;
            }
            voffset += 4;
            tvb_ensure_bytes_exist(tvb, voffset, value1);
            number_of_items = tvb_get_letohl(tvb, voffset);
            voffset = voffset+4;
            for (r=1; r<=number_of_items; r++)
            {
                value1 = tvb_get_letohl(tvb, voffset); /* length of field */
                length_remaining = tvb_captured_length_remaining(tvb, voffset);
                if(length_remaining == -1 || value1 > (uint32_t) length_remaining)
                {
                    break;
                }
                voffset += 4;
                proto_tree_add_item(nvtree, hf_value_bytes, tvb, voffset, value1, ENC_NA);
                voffset += value1;
                voffset += (value1%2);
            }
            break;
        case 0x00000015:        /* Stream */
            value1 = tvb_get_letohl(tvb, voffset); /* length of field */
            length_remaining = tvb_captured_length_remaining(tvb, voffset);
            if(length_remaining == -1 || value1 > (uint32_t) length_remaining)
            {
                break;
            }
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset, 4, value1, "No value, Open stream file for data.");
            voffset += 4;
            voffset += value1;
            voffset += (value1%2);
            break;
        case 0x00000008:        /* Signed Integer */
        case 0x00000016:        /* Counter */
        case 0x0000001b:        /* Interval */
            value1 = tvb_get_letohl(tvb, voffset); /* length of field */
            voffset = voffset+4;
            value2 = tvb_get_letohl(tvb, voffset); /* Value */
            if (strcmp(vvalues->vstring, "zendmSearchType")==0) {
                proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                           value1, value2,
                                           "Value (%d) = %s", value2,
                                           val_to_str(value2, zensearchenum, "Unknown: %d"));
            }
            else
            {
                proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                           value1, value2, "Value %d", value2);
            }
            voffset = voffset+4;
            break;
        case 0x0000000b:        /* Fax Number */
            value1 = tvb_get_letohl(tvb, voffset); /* length of field */
            voffset = voffset+4;
            vvalues->vstring = get_string(tvb, voffset, value1);
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  value1, vvalues->vstring);
            voffset = check_offset_addition(voffset, value1, nvtree, pinfo, tvb);
            voffset += align_4(tvb, voffset);
            break;
        case 0x0000000c:        /* Network Address */
            value1 = tvb_get_letohl(tvb, voffset); /* length of field */
            voffset = voffset + 4;
            value2 = tvb_get_letohl(tvb, voffset); /* type of Protocol */
            valuestr = val_to_str_const(value2, nds_protocol_type, "(Undefined Protocol)");
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       value1, value2, valuestr, value2);
            voffset = voffset+4;
            value3 = tvb_get_letohl(tvb, voffset); /* length of address */
            voffset = voffset+4;
            switch (value2)
            {
            case NDS_PTYPE_IPX:
                proto_tree_add_item(nvtree, hf_nds_net, tvb, voffset, 4, ENC_BIG_ENDIAN);
                proto_tree_add_item(nvtree, hf_nds_node, tvb, voffset+4, 6, ENC_NA);
                proto_tree_add_item(nvtree, hf_nds_socket, tvb, voffset+10, 2, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_IP:
                if (value3 > 4) {
                    proto_tree_add_item(nvtree, hf_nds_port, tvb, voffset, 2, ENC_BIG_ENDIAN);
                    voffset += 2;
                }
                proto_tree_add_item(nvtree, hf_add_ref_ip, tvb, voffset, 4, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_UDP:
                if (value3 > 4) {
                    proto_tree_add_item(nvtree, hf_nds_port, tvb, voffset, 2, ENC_BIG_ENDIAN);
                    voffset += 2;
                }
                proto_tree_add_item(nvtree, hf_add_ref_udp, tvb, voffset, 4, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_TCP:
                proto_tree_add_item(nvtree, hf_nds_port, tvb, voffset, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(nvtree, hf_add_ref_tcp, tvb, voffset+2, 4, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_URL:
            case NDS_PTYPE_DNS:
                vvalues->vstring = get_string(tvb, voffset, value3);
                proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                      value3, vvalues->vstring);
                break;
            default:
                break;
            }
            voffset = check_offset_addition(voffset, value3, nvtree, pinfo, tvb);
            voffset += align_4(tvb, voffset);
            break;
        case 0x0000000f:        /* File System Path */
            /*value1 = tvb_get_letohl(tvb, voffset);*/ /* length of field */
            voffset = voffset + 4;
            value2 = tvb_get_letohl(tvb, voffset); /* Name Space */
            valuestr = val_to_str_const(value2, name_space_type, "Unknown Name Space");
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  4, valuestr);
            voffset = voffset+4;
            value3 = tvb_get_letohl(tvb, voffset); /* Length of Volume name */
            voffset = voffset+4;
            vvalues->vstring = get_string(tvb, voffset, value3);
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  value3, vvalues->vstring);
            voffset = check_offset_addition(voffset, value3, nvtree, pinfo, tvb);
            voffset += align_4(tvb, voffset);
            value4 = tvb_get_letohl(tvb, voffset); /* Length of Path name */
            voffset = voffset+4;
            vvalues->vstring = get_string(tvb, voffset, value4);
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  value4, vvalues->vstring);
            voffset = check_offset_addition(voffset, value4, nvtree, pinfo, tvb);
            voffset += align_4(tvb, voffset);
            break;
        case 0x00000010:        /* Replica Pointer */
            /*value1 = tvb_get_letohl(tvb, voffset);*/ /* length of field */
            voffset = voffset + 4;
            value2 = tvb_get_letohl(tvb, voffset); /* Length of Server name */
            voffset = voffset+4;
            vvalues->vstring = get_string(tvb, voffset, value2);
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  value2, vvalues->vstring);
            voffset = check_offset_addition(voffset, value2, nvtree, pinfo, tvb);
            voffset += align_4(tvb, voffset);
            proto_tree_add_item(nvtree, hf_replica_type, tvb, voffset, 2, ENC_LITTLE_ENDIAN);
            voffset = voffset+2;
            proto_tree_add_item(nvtree, hf_replica_state, tvb, voffset, 2, ENC_LITTLE_ENDIAN);
            voffset = voffset+2;
            proto_tree_add_item(nvtree, hf_replica_number, tvb, voffset, 4, ENC_LITTLE_ENDIAN);
            voffset = voffset+4;
            if((vvalues->pflags & 0x8000) | (vvalues->pflags & 0x4000))
            {
                /* If this request flag is set then this is a server. Server structures
                 * include the RootID as part of the replica data. */
                proto_tree_add_item(nvtree, hf_nds_partition_root_id, tvb, voffset, 4, ENC_BIG_ENDIAN);
                voffset += 4;
            }
            number_of_items = tvb_get_letohl(tvb, voffset);  /* Number of Addresses */
            aditem = proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                                4, number_of_items, "Number of Addresses: %u", number_of_items);

            adtree = proto_item_add_subtree(aditem, ett_nds);
            voffset = voffset+4;
            for (r=1; r <= number_of_items; r++)
            {
                /* Trap for end of packet */
                if(tvb_captured_length_remaining(tvb, voffset)<12)
                {
                    THROW(ReportedBoundsError);
                }
                voffset += align_4(tvb, voffset);
                value4 = tvb_get_letohl(tvb, voffset); /* type of Protocol */
                valuestr = val_to_str_const(value4, nds_protocol_type, "(Undefined Protocol)");
                proto_tree_add_uint_format(adtree, hf_nds_uint32value, tvb, voffset,
                                           4, value4, valuestr, value4);
                voffset = voffset+4;
                value5 = tvb_get_letohl(tvb, voffset); /* length of address */
                voffset = voffset+4;
                switch (value4)
                {
                case NDS_PTYPE_IPX:
                    proto_tree_add_item(adtree, hf_nds_net, tvb, voffset, 4, ENC_BIG_ENDIAN);
                    proto_tree_add_item(adtree, hf_nds_node, tvb, voffset+4, 6, ENC_NA);
                    proto_tree_add_item(adtree, hf_nds_socket, tvb, voffset+10, 2, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_IP:
                    proto_tree_add_item(adtree, hf_nds_port, tvb, voffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(adtree, hf_add_ref_ip, tvb, voffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_UDP:
                    proto_tree_add_item(adtree, hf_nds_port, tvb, voffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(adtree, hf_add_ref_udp, tvb, voffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_TCP:
                    proto_tree_add_item(adtree, hf_nds_port, tvb, voffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(adtree, hf_add_ref_tcp, tvb, voffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_URL:
                case NDS_PTYPE_DNS:
                    vvalues->vstring = get_string(tvb, voffset, value5);
                    proto_tree_add_string(adtree, hf_value_string, tvb, voffset,
                                          value5, vvalues->vstring);
                    break;
                default:
                    break;
                }
                voffset = check_offset_addition(voffset, value5, adtree, pinfo, tvb);
            }
            voffset += align_4(tvb, voffset);
            break;
        case 0x00000011:        /* Object ACL */
            /*value1 = tvb_get_letohl(tvb, voffset);*/ /* Length of Field */
            voffset = voffset + 4;
            value2 = tvb_get_letohl(tvb, voffset);
            voffset = voffset + 4;
            vvalues->vstring = get_string(tvb, voffset, value2); /* Unicode String */
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  value2, vvalues->vstring);
            if (strcmp(vvalues->vstring, "[Entry Rights]")) {
                entry_rights=true;
            }
            else
            {
                entry_rights=false;
            }
            voffset = check_offset_addition(voffset, value2, nvtree, pinfo, tvb);
            voffset += align_4(tvb, voffset);
            value3 = tvb_get_letohl(tvb, voffset);
            voffset = voffset + 4;
            vvalues->vstring = get_string(tvb, voffset, value3); /* Unicode Subject Name */
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  value3, vvalues->vstring);
            voffset = check_offset_addition(voffset, value3, nvtree, pinfo, tvb);
            voffset += align_4(tvb, voffset);
            /* Entry or Attribute Privileges */
            if (entry_rights) {
                /* if Entries then use these bits */
                static int * const entries[] = {
                    &hf_nds_compare_attributes,
                    &hf_nds_read_attribute,
                    &hf_nds_write_add_delete_attribute,
                    &hf_nds_add_delete_self,
                    &hf_nds_privilege_not_defined,
                    &hf_nds_supervisor,
                    &hf_nds_inheritance_control,
                    &hf_bit8vflags,
                    &hf_bit9vflags,
                    &hf_bit10vflags,
                    &hf_bit11vflags,
                    &hf_bit12vflags,
                    &hf_bit13vflags,
                    &hf_bit14vflags,
                    &hf_bit15vflags,
                    &hf_bit16vflags,
                    NULL
                };

                proto_tree_add_bitmask(nvtree, tvb, voffset, hf_nds_privileges, ett_ncp, entries, ENC_LITTLE_ENDIAN);
            }
            else
            {
                /* if attribute rights then do these bits */
                static int * const rights[] = {
                    &hf_nds_browse_entry,
                    &hf_nds_add_entry,
                    &hf_nds_delete_entry,
                    &hf_nds_rename_entry,
                    &hf_nds_supervisor_entry,
                    &hf_nds_entry_privilege_not_defined,
                    &hf_nds_inheritance_control,
                    &hf_bit8vflags,
                    &hf_bit9vflags,
                    &hf_bit10vflags,
                    &hf_bit11vflags,
                    &hf_bit12vflags,
                    &hf_bit13vflags,
                    &hf_bit14vflags,
                    &hf_bit15vflags,
                    &hf_bit16vflags,
                    NULL
                };

                proto_tree_add_bitmask(nvtree, tvb, voffset, hf_nds_privileges, ett_ncp, rights, ENC_LITTLE_ENDIAN);
            }
            voffset = voffset+4;
            voffset += align_4(tvb, voffset);
            break;
        case 0x00000013:        /* Time Stamp */
            value1 = tvb_get_letohl(tvb, voffset);         /* Seconds */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value1, "Length of Record: %u", value1);
            voffset = voffset+4;
            ns.secs = tvb_get_letohl(tvb, voffset);
            ns.nsecs = 0;
            proto_tree_add_time_format(nvtree, hf_nds_ds_time, tvb, voffset, 4,
                &ns, "Timestamp: %s", abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
            voffset = voffset + 4;
            proto_tree_add_item(nvtree, hf_nds_rnum, tvb, voffset, 2, ENC_LITTLE_ENDIAN);
            voffset = voffset+2;
            proto_tree_add_item(nvtree, hf_nds_revent, tvb, voffset, 2, ENC_LITTLE_ENDIAN);
            voffset = voffset+2;
            voffset += align_4(tvb, voffset);
            break;
        case 0x00000017:        /* Back Link */
            value1 = tvb_get_letohl(tvb, voffset);         /* Length */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value1, "Length of Record %08x", value1);
            voffset = voffset+4;
            value2 = tvb_get_letohl(tvb, voffset);         /* Remote ID */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value2, "Remote ID %08x", value2);
            voffset = voffset+4;
            value3 = tvb_get_letohl(tvb, voffset);         /* Length of string */
            voffset = voffset+4;
            vvalues->vstring = get_string(tvb, voffset, value3);
            proto_tree_add_string_format(nvtree, hf_value_string, tvb, voffset,
                                         value3, vvalues->vstring,
                                         "Server Distinguished Name - %s", vvalues->vstring);
            voffset = voffset+value3;
            voffset += align_4(tvb, voffset);
            break;
        case 0x00000018:        /* Time */
            voffset += 4; /* This is the length of the time data no need to decode, always 4 bytes */
            ns.secs = tvb_get_letohl(tvb, voffset);
            ns.nsecs = 0;
            proto_tree_add_time_format(nvtree, hf_nds_ds_time, tvb, voffset, 4,
                &ns, "Time: %s", abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
            voffset = voffset + 4;
            break;
        case 0x00000019:        /* Typed Name */
            value1 = tvb_get_letohl(tvb, voffset);         /* Length */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value1, "Length of Record %08x", value1);
            voffset = voffset+4;
            value2 = tvb_get_letohl(tvb, voffset);         /* Level */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value2, "Level %d", value2);
            voffset = voffset+4;
            value3 = tvb_get_letohl(tvb, voffset);         /* Interval */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value3, "Interval %d", value3);
            voffset = voffset+4;
            value4 = tvb_get_letohl(tvb, voffset);         /* Distinguished Name */
            voffset = voffset+4;
            vvalues->vstring = get_string(tvb, voffset, value4);
            proto_tree_add_string_format(nvtree, hf_value_string, tvb, voffset,
                                         value4, vvalues->vstring,
                                         "Distinguished Name - %s", vvalues->vstring);
            voffset = voffset+value4;
            voffset += align_4(tvb, voffset);
            break;
        case 0x0000001a:        /* Hold */
            value1 = tvb_get_letohl(tvb, voffset);         /* Length */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value1, "Length of Record %08x", value1);
            voffset = voffset+4;
            value2 = tvb_get_letohl(tvb, voffset);         /* Amount */
            proto_tree_add_uint_format(nvtree, hf_nds_uint32value, tvb, voffset,
                                       4, value2, "Amount %d", value2);
            voffset = voffset+4;
            value3 = tvb_get_letohl(tvb, voffset);         /* Subject */
            voffset = voffset+4;
            vvalues->vstring = get_string(tvb, voffset, value3);
            proto_tree_add_string_format(nvtree, hf_value_string, tvb, voffset,
                                         value3, vvalues->vstring,
                                         "Subject - %s", vvalues->vstring);
            voffset = voffset+value3;
            voffset += align_4(tvb, voffset);
            break;
        case 0x00000001:        /* Distinguished Name */
        case 0x00000002:        /* Case Sensitive Unicode String */
        case 0x00000003:        /* Non Case Sensitive Unicode String */
        case 0x00000004:        /* Printable String */
        case 0x00000005:        /* Numeric String */
        case 0x0000000a:        /* Telephone Number */
        case 0x0000000e:        /* Email Address */
        case 0x00000014:        /* Class Name */
        default:
            value1 = tvb_get_letohl(tvb, voffset);
            voffset = voffset + 4;
            if (strcmp(vvalues->vstring, "zendmSearchOrder")==0) {
                vvalues->vstring = get_string(tvb, voffset, value1);
                if (strcmp(vvalues->vstring, "0")==0) {
                    vvalues->vstring = "Value (0) = Object";
                }
                else if (strcmp(vvalues->vstring, "1")==0) {
                    vvalues->vstring = "Value (1) = Group";
                }
                else if (strcmp(vvalues->vstring, "2")==0) {
                    vvalues->vstring = "Value (2) = Container";
                }
                else if (strcmp(vvalues->vstring, "01")==0) {
                    vvalues->vstring = "Value (01) = Object, Group";
                }
                else if (strcmp(vvalues->vstring, "02")==0) {
                    vvalues->vstring = "Value (02) = Object, Container";
                }
                else if (strcmp(vvalues->vstring, "10")==0) {
                    vvalues->vstring = "Value (10) = Group, Object";
                }
                else if (strcmp(vvalues->vstring, "12")==0) {
                    vvalues->vstring = "Value (12) = Group, Container";
                }
                else if (strcmp(vvalues->vstring, "20")==0) {
                    vvalues->vstring = "Value (20) = Container, Object";
                }
                else if (strcmp(vvalues->vstring, "21")==0) {
                    vvalues->vstring = "Value (21) = Container, Group";
                }
                else if (strcmp(vvalues->vstring, "012")==0) {
                    vvalues->vstring = "Value (012) = Object, Group, Container";
                }
                else if (strcmp(vvalues->vstring, "021")==0) {
                    vvalues->vstring = "Value (021) = Object, Container, Group";
                }
                else if (strcmp(vvalues->vstring, "102")==0) {
                    vvalues->vstring = "Value (102) = Group, Object, Container";
                }
                else if (strcmp(vvalues->vstring, "120")==0) {
                    vvalues->vstring = "Value (120) = Group, Container, Object";
                }
                else if (strcmp(vvalues->vstring, "201")==0) {
                    vvalues->vstring = "Value (201) = Container, Object, Group";
                }
                else if (strcmp(vvalues->vstring, "210")==0) {
                    vvalues->vstring = "Value (210) = Container, Group, Object";
                }
            }
            else
            {
                vvalues->vstring = get_string(tvb, voffset, value1);
            }
            proto_tree_add_string(nvtree, hf_value_string, tvb, voffset,
                                  value1, vvalues->vstring);
            voffset = voffset + value1;
            voffset += align_4(tvb, voffset);
            break;
        }
        voffset += align_4(tvb, voffset);
    }
    vvalues->voffset=voffset;
    return;
}

static uint32_t
print_es_type(proto_tree *estree, tvbuff_t *tvb, nds_val *values, uint32_t vtype, uint32_t ioffset)
{
    uint32_t        value1;
    uint32_t        value2;
    uint32_t        value3;
    uint32_t        value4;
    uint32_t        value5;
    uint32_t        number_of_referrals;
    uint32_t        r;
    uint32_t        i;
    proto_tree      *nestree;
    proto_item      *nesitem;
    proto_tree      *sub1tree;
    proto_item      *sub1item;
    proto_tree      *sub2tree;
    const char      *vstring="";
    nstime_t        ns;

    switch (vtype)
    {
    case 0: /* No Specifier Type */
        /* ES Type */
        proto_tree_add_item(estree, hf_es_value, tvb, ioffset,
                            4, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 4;
        break;
    case 1: /* Unicode String */
        value1 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, value1);
        proto_tree_add_string_format(estree, hf_mv_string, tvb, ioffset,
                                     value1, values->vstring, "Delimiter ->%s", values->vstring);
        ioffset=ioffset + value1;
        ioffset += align_4(tvb, ioffset);
        value2 = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, value2);
        proto_tree_add_string(estree, hf_mv_string, tvb, ioffset,
                              value2, values->vstring);
        values->voffset = check_offset_addition(ioffset, value2, estree, NULL, tvb);
        ioffset = values->voffset;
        ioffset += align_4(tvb, ioffset);
        break;
    case 2: /* Based */
        value1 = tvb_get_letohl(tvb, ioffset);   /* ES Type */
        vstring = val_to_str_const(value1, es_type, "No ES Type Found");
        nesitem = proto_tree_add_string_format(estree, hf_es_type, tvb, ioffset,
                                               4, vstring, "Base Context Type - %s", vstring);
        nestree = proto_item_add_subtree(nesitem, ett_nds);
        ioffset = ioffset + 4;
        switch (value1)
        {
        case 0: /* No Specifier Type */
            /* ES Type */
            proto_tree_add_item(nestree, hf_es_value, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
            break;
        case 1: /* Unicode String */
            value2 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string_format(nestree, hf_mv_string, tvb, ioffset,
                                         value2, values->vstring, "Delimiter ->%s", values->vstring);
            ioffset = check_offset_addition(ioffset, value2, nestree, NULL, tvb);
            ioffset += align_4(tvb, ioffset);
            value3 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value3);
            proto_tree_add_string(nestree, hf_mv_string, tvb, ioffset,
                                  value3, values->vstring);
            values->voffset=ioffset + value3;
            ioffset = values->voffset;
            ioffset += align_4(tvb, ioffset);
            break;
        case 2: /* Based */
            break;
        case 3: /* Hinted */
            break;
        case 4: /* Tuned */
            value2 = tvb_get_letohl(tvb, ioffset);   /* Count */
            proto_tree_add_item(nestree, hf_es_rdn_count, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
            for (r = 1 ; r <= value2; r++ )
            {
                ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                ns.nsecs = 0;
                proto_tree_add_time_format(nestree, hf_es_seconds, tvb, ioffset,
                                           4, &ns, "Timestamp: %s",
                                           abs_time_secs_to_str(wmem_packet_scope(), ns.secs, ABSOLUTE_TIME_LOCAL, true));
                ioffset = ioffset + 4;
                proto_tree_add_item(nestree, hf_nds_replica_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
                proto_tree_add_item(nestree, hf_nds_event_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
            }
            value4 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value4);
            proto_tree_add_string(nestree, hf_mv_string, tvb, ioffset,
                                  value4, values->vstring);
            ioffset=ioffset + value4;
            ioffset += align_4(tvb, ioffset);
            value5 = tvb_get_letohl(tvb, ioffset);   /* RDN */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value5);
            proto_tree_add_string(nestree, hf_rdn_string, tvb, ioffset,
                                  value5, values->vstring);
            ioffset=ioffset + value5;
            ioffset += align_4(tvb, ioffset);
            break;
        case 5: /* GUID */
        case 6: /* ID32 */
        case 7: /* Count */
        default:
            /* ES Type */
            /* XXX: nestree rather than estree ?? */
            proto_tree_add_item(estree, hf_es_value, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
            break;
        }
        value1 = tvb_get_letohl(tvb, ioffset);   /* ES Type */
        vstring = val_to_str_const(value1, es_type, "No ES Type Found");
        nesitem = proto_tree_add_string_format(estree, hf_es_type, tvb, ioffset,
                                               4, vstring, "Object Name Type - %s", vstring);
        nestree = proto_item_add_subtree(nesitem, ett_nds);
        ioffset = ioffset + 4;
        switch (value1)
        {
        case 0: /* No Specifier Type */
            /* ES Type */
            proto_tree_add_item(nestree, hf_es_value, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
            break;
        case 1: /* Unicode String */
            value2 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string_format(nestree, hf_mv_string, tvb, ioffset,
                                         value2, values->vstring, "Delimiter ->%s", values->vstring);
            ioffset = check_offset_addition(ioffset, value2, nestree, NULL, tvb);
            ioffset += align_4(tvb, ioffset);
            value3 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value3);
            proto_tree_add_string(nestree, hf_mv_string, tvb, ioffset,
                                  value3, values->vstring);
            values->voffset=ioffset + value3;
            ioffset = values->voffset;
            ioffset += align_4(tvb, ioffset);
            break;
        case 2: /* Based */
            break;
        case 3: /* Hinted */
            break;
        case 4: /* Tuned */
            /* Count */
            proto_tree_add_item_ret_uint(nestree, hf_es_rdn_count, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN, &value2);
            ioffset = ioffset + 4;
            for (r = 1 ; r <= value2; r++ )
            {
                ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                ns.nsecs = 0;
                proto_tree_add_time_format(nestree, hf_es_seconds, tvb, ioffset,
                                           4, &ns, "Timestamp: %s",
                                           abs_time_secs_to_str(wmem_packet_scope(), ns.secs, ABSOLUTE_TIME_LOCAL, true));
                ioffset = ioffset + 4;
                proto_tree_add_item(nestree, hf_nds_replica_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
                proto_tree_add_item(nestree, hf_nds_event_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
            }
            value4 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value4);
            proto_tree_add_string(nestree, hf_mv_string, tvb, ioffset,
                                  value4, values->vstring);
            ioffset=ioffset + value4;
            ioffset += align_4(tvb, ioffset);
            value5 = tvb_get_letohl(tvb, ioffset);   /* RDN */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value5);
            proto_tree_add_string(nestree, hf_rdn_string, tvb, ioffset,
                                  value5, values->vstring);
            ioffset=ioffset + value5;
            ioffset += align_4(tvb, ioffset);
            break;
        case 5: /* GUID */
        case 6: /* ID32 */
        case 7: /* Count */
        default:
            /* ES Type */
            /* XXX: nestree rather than estree ?? */
            proto_tree_add_item(estree, hf_es_value, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
            break;
        }
        break;
    case 3: /* Hinted */
        number_of_referrals = tvb_get_letohl(tvb, ioffset);

        for (r = 1 ; r <= number_of_referrals; r++ )
        {
            sub1item = proto_tree_add_uint_format(estree, hf_referral_record, tvb, 6, 0,
                                                  r, "NDS Referral Record #%u", r);
            sub1tree = proto_item_add_subtree(sub1item, ett_nds);

            proto_tree_add_item_ret_uint(sub1tree, hf_referral_addcount, tvb, ioffset, 4, ENC_LITTLE_ENDIAN, &value1);

            ioffset = ioffset + 4;
            for (i = 1 ; i <= value1; i++ )
            {
                value2 = tvb_get_letohl(tvb, ioffset);
                values->vstring = val_to_str_const(value2, nds_protocol_type, "(Undefined Protocol)");
                proto_tree_add_uint_format(sub1tree, hf_nds_uint32value, tvb, ioffset,
                                           4, value2, vstring, value2);
                ioffset = ioffset+4;
                value3 = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset+4;
                switch (value2)
                {
                case NDS_PTYPE_IPX:
                    proto_tree_add_item(sub1tree, hf_nds_net, tvb, ioffset, 4, ENC_BIG_ENDIAN);
                    proto_tree_add_item(sub1tree, hf_nds_node, tvb, ioffset+4, 6, ENC_NA);
                    proto_tree_add_item(sub1tree, hf_nds_socket, tvb, ioffset+10, 2, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_IP:
                    proto_tree_add_item(sub1tree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(sub1tree, hf_add_ref_ip, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_UDP:
                    proto_tree_add_item(sub1tree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(sub1tree, hf_add_ref_udp, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_TCP:
                    proto_tree_add_item(sub1tree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(sub1tree, hf_add_ref_tcp, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_URL:
                case NDS_PTYPE_DNS:
                    values->vstring = get_string(tvb, ioffset, value3);
                    proto_tree_add_string(sub1tree, hf_value_string, tvb, ioffset,
                                          value3, values->vstring);
                    break;
                default:
                    break;
                }
                ioffset = check_offset_addition(ioffset, value3, sub1tree, NULL, tvb);
                ioffset += align_4(tvb, ioffset);
            }

        }
        value1 = tvb_get_letohl(tvb, ioffset);   /* ES Type */
        vstring = val_to_str_const(value1, es_type, "No ES Type Found");
        nesitem = proto_tree_add_string_format(estree, hf_es_type, tvb, ioffset,
                                               4, vstring, "Object Name Type - %s", vstring);
        nestree = proto_item_add_subtree(nesitem, ett_nds);
        ioffset = ioffset + 4;
        switch (value1)
        {
        case 0: /* No Specifier Type */
            /* ES Type */
            proto_tree_add_item(nestree, hf_es_value, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
            break;
        case 1: /* Unicode String */
            value2 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string_format(nestree, hf_mv_string, tvb, ioffset,
                                         value2, values->vstring, "Delimiter ->%s", values->vstring);
            ioffset = check_offset_addition(ioffset, value2, nestree, NULL, tvb);
            ioffset += align_4(tvb, ioffset);
            value3 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value3);
            proto_tree_add_string(nestree, hf_mv_string, tvb, ioffset,
                                  value3, values->vstring);
            values->voffset=check_offset_addition(ioffset, value3, nestree, NULL, tvb);
            ioffset = values->voffset;
            ioffset += align_4(tvb, ioffset);
            break;
        case 2: /* Based */
            break;
        case 3: /* Hinted */
            break;
        case 4: /* Tuned */
            /* Count */
            proto_tree_add_item_ret_uint(nestree, hf_es_rdn_count, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN, &value2);
            ioffset = ioffset + 4;
            for (r = 1 ; r <= value2; r++ )
            {
                ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                ns.nsecs = 0;
                proto_tree_add_time_format(nestree, hf_es_seconds, tvb, ioffset,
                                           4, &ns, "Timestamp: %s",
                                           abs_time_secs_to_str(wmem_packet_scope(), ns.secs, ABSOLUTE_TIME_LOCAL, true));
                ioffset = ioffset + 4;
                proto_tree_add_item(nestree, hf_nds_replica_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
                proto_tree_add_item(nestree, hf_nds_event_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
            }
            value4 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value4);
            proto_tree_add_string(nestree, hf_mv_string, tvb, ioffset,
                                  value4, values->vstring);
            ioffset = check_offset_addition(ioffset, value4, nestree, NULL, tvb);
            ioffset += align_4(tvb, ioffset);
            value5 = tvb_get_letohl(tvb, ioffset);   /* RDN */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value5);
            proto_tree_add_string(nestree, hf_rdn_string, tvb, ioffset,
                                  value5, values->vstring);
            ioffset = check_offset_addition(ioffset, value5, nestree, NULL, tvb);
            ioffset += align_4(tvb, ioffset);
            break;
        case 5: /* GUID */
        case 6: /* ID32 */
        case 7: /* Count */
        default:
            /* ES Type */
            /* XXX: nestree rather than estree ?? */
            proto_tree_add_item(estree, hf_es_value, tvb, ioffset,
                                4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
            break;
        }
        break;
    case 4: /* Tuned */
        value1 = tvb_get_letohl(tvb, ioffset);
        sub1item = proto_tree_add_uint_format(estree, hf_es_rdn_count, tvb, ioffset,
                                              4, value1, "Number of RDN Items %u", value1);
        sub1tree = proto_item_add_subtree(sub1item, ett_nds);
        ioffset = ioffset + 4;
        for (r = 1 ; r <= value1; r++ )
        {
            sub2tree = proto_tree_add_subtree_format(sub1tree, tvb, ioffset, 10, ett_nds, NULL, "Item %u", r);

            ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
            ns.nsecs = 0;
            proto_tree_add_time_format(sub2tree, hf_es_seconds, tvb, ioffset,
                                       4, &ns, "Timestamp: %s",
                                       abs_time_secs_to_str(wmem_packet_scope(), ns.secs, ABSOLUTE_TIME_LOCAL, true));
            ioffset = ioffset + 4;
            proto_tree_add_item(sub2tree, hf_nds_replica_num, tvb, ioffset,
                                2, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 2;
            proto_tree_add_item(sub2tree, hf_nds_event_num, tvb, ioffset,
                                2, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 2;
        }
        value3 = tvb_get_letohl(tvb, ioffset);   /* Delimiter Set */
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, value3);
        proto_tree_add_string(sub1tree, hf_mv_string, tvb, ioffset,
                              value3, values->vstring);
        ioffset = check_offset_addition(ioffset, value3, sub1tree, NULL, tvb);
        ioffset += align_4(tvb, ioffset);
        value4 = tvb_get_letohl(tvb, ioffset);   /* RDN */
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, value4);
        proto_tree_add_string(sub1tree, hf_rdn_string, tvb, ioffset,
                              value4, values->vstring);
        ioffset=check_offset_addition(ioffset, value4, sub1tree, NULL, tvb);
        ioffset += align_4(tvb, ioffset);
        break;
    case 5: /* GUID */
    case 6: /* ID32 */
    case 7: /* Count */
    default:
        /* ES Type */
        proto_tree_add_item(estree, hf_es_value, tvb, ioffset,
                            4, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 4;
        break;
    }
    return ioffset;
}


static void process_set_filter(proto_tree* , tvbuff_t*, packet_info*, nds_val*);

static void
process_search_expression(proto_tree *it_tree, tvbuff_t *tvb, nds_val *values)
{
    uint32_t    search_tag, ioffset;
    const char *search_string;

    ioffset = values->voffset;
    search_tag = tvb_get_letohl(tvb, ioffset); /* Get next search operation tag */
    search_string = val_to_str_const(search_tag, itersearchenum, "(No Search Operation Type Found!)");
    proto_tree_add_uint_format(it_tree, hf_iter_search, tvb, ioffset, 4,
                               search_tag, "Search Operation Type: %d, (0x%04x), %s",
                               search_tag, search_tag, search_string);
    ioffset += 4;
    switch (search_tag)
    {
    case NDS_SEARCH_EQUAL:
    case NDS_SEARCH_GREATER_OR_EQUAL:
    case NDS_SEARCH_LESS_OR_EQUAL:
    case NDS_SEARCH_APPROX:
    case NDS_SEARCH_ATTR_FLAGS:
    case NDS_SEARCH_ATTR_HAS_FLAG:
        /* start of DCWPutAttribute */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutAttribute */

        ioffset += align_4(tvb, ioffset);

        /* start of DCWPutValue */
        proto_tree_add_item(it_tree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 4;
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutValue */

        break;
    case NDS_SEARCH_PRESENT:
        /* start of DCWPutAttribute */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
        /* end of DCWPutAttribute */
        break;

    case NDS_SEARCH_RDN:
        /* print the relative distinguished name. This includes context info... */
#if 0
        if (err = DCWPutRDN(context, cur, limit, item->data))
            return err;
#endif

        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        break;
    case NDS_SEARCH_BASE_CLASS:
    case NDS_SEARCH_ENTRY_FLAGS:
    case NDS_SEARCH_ENTRY_HAS_FLAG:
    case NDS_SEARCH_VALUE_FLAGS:
    case NDS_SEARCH_VALUE_HAS_FLAG:
        /* start of DCWPutValue */
#if 0
        proto_tree_add_item(it_tree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 4;
#endif
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutValue */
        break;
    case DCS_VALUE_GE_WITH_ATTR:        /* Deprecated, use DS_SEARCH_VALUE_MTS_GE */
    case NDS_SEARCH_VALUE_MTS_GE:
    case NDS_SEARCH_VALUE_MTS_G:
    case NDS_SEARCH_VALUE_MTS_LE:
    case NDS_SEARCH_VALUE_MTS_L:
    case NDS_SEARCH_VALUE_MTS_EQ:
    case NDS_SEARCH_VALUE_MTS_EQ_APPROX:
    case NDS_SEARCH_VALUE_CTS_GE:
    case NDS_SEARCH_VALUE_CTS_G:
    case NDS_SEARCH_VALUE_CTS_LE:
    case NDS_SEARCH_VALUE_CTS_L:
    case NDS_SEARCH_VALUE_CTS_EQ:
    case NDS_SEARCH_VALUE_CTS_EQ_APPROX:
        /* start of DCWPutAttribute */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutAttribute */

        ioffset += align_4(tvb, ioffset);

        /* start of DCWPutValue */
        proto_tree_add_item(it_tree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 4;
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutValue */
        break;
    case DCS_MOD_GE_WITH_ATTR:        /* Deprecated, use DS_SEARCH_ENTRY_MTS */
    case NDS_SEARCH_ENTRY_MTS_GE:
    case NDS_SEARCH_ENTRY_MTS_G:
    case NDS_SEARCH_ENTRY_MTS_LE:
    case NDS_SEARCH_ENTRY_MTS_L:
    case NDS_SEARCH_ENTRY_MTS_EQ:
    case NDS_SEARCH_ENTRY_MTS_EQ_APPROX:
    case NDS_SEARCH_ENTRY_CTS_GE:
    case NDS_SEARCH_ENTRY_CTS_G:
    case NDS_SEARCH_ENTRY_CTS_LE:
    case NDS_SEARCH_ENTRY_CTS_L:
    case NDS_SEARCH_ENTRY_CTS_EQ:
    case NDS_SEARCH_ENTRY_CTS_EQ_APPROX:
        /* start of DCWPutAttribute */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutAttribute */

        ioffset += align_4(tvb, ioffset);

        /* start of DCWPutValue */
        proto_tree_add_item(it_tree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 4;
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutValue */

        break;
    case NDS_SEARCH_EID:
    case NDS_SEARCH_ENTRY_SUBCOUNT_GE:
    case NDS_SEARCH_ENTRY_SUBCOUNT_G:
    case NDS_SEARCH_ENTRY_SUBCOUNT_LE:
    case NDS_SEARCH_ENTRY_SUBCOUNT_L:
    case NDS_SEARCH_ENTRY_SUBCOUNT_EQ:
        /* start of DCWPutValue */
        proto_tree_add_item(it_tree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 4;
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                              values->vvalue, values->vstring);
        ioffset += values->vvalue;
        /* end of DCWPutValue */

        break;

    default: /* Unknown Iteration search Item type */
        if (tvb_captured_length_remaining(tvb, ioffset) < 4) {
                THROW(ReportedBoundsError);
        }
        break;
    }
    ioffset += align_4(tvb, ioffset);
    values->voffset = ioffset;
    return;
}

static void
process_search_subexpression(proto_tree *it_tree, tvbuff_t *tvb, packet_info *pinfo, nds_val *values)
{
    proto_tree  *it_subtree, *it_subtree1;
    proto_item  *it_subitem;
    uint32_t    i, ioffset, number_of_items;

    ioffset = values->voffset;
    if (values->vvalue != NDS_SEARCH_NOT) {
        number_of_items = tvb_get_letohl(tvb, ioffset);
        it_subitem = proto_tree_add_item(it_tree, hf_this_count, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        it_subtree = proto_item_add_subtree(it_subitem, ett_nds);
        ioffset += 4;
        for (i = 0; i < number_of_items; i++)
        {
            it_subtree1 = proto_tree_add_subtree_format(it_subtree, tvb, ioffset, -1, ett_nds, NULL, "Item #: %u", i+1);

            values->voffset = ioffset;
            process_set_filter(it_subtree1, tvb, pinfo, values);
            ioffset = values->voffset;

            if (tvb_captured_length_remaining(tvb, ioffset) < 4) {
                THROW(ReportedBoundsError);
                break;
            }

        }
    }
    values->voffset = ioffset;
    return;
}

static void
process_search_match(proto_tree *it_tree, tvbuff_t *tvb, nds_val *values)
{
    uint32_t    ioffset;

    ioffset = values->voffset;

    values->vvalue = tvb_get_letohl(tvb, ioffset);
    ioffset += 4;
    proto_tree_add_item(it_tree, hf_nds_oid, tvb, ioffset, values->vvalue, ENC_NA);
    ioffset += values->vvalue;

    ioffset += align_4(tvb, ioffset);

    proto_tree_add_item(it_tree, hf_iter_ans, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
    ioffset += 4;

    ioffset += align_4(tvb, ioffset);

    /* start of DCWPutAttribute */
    values->vvalue = tvb_get_letohl(tvb, ioffset);
    ioffset = ioffset + 4;
    values->vstring = get_string(tvb, ioffset, values->vvalue);
    proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
            values->vvalue, values->vstring);
    ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
    /* end of DCWPutAttribute */

    ioffset += align_4(tvb, ioffset);

    /* start of DCWPutValue */
    proto_tree_add_item(it_tree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
    ioffset = ioffset + 4;
    values->vvalue = tvb_get_letohl(tvb, ioffset);
    ioffset = ioffset + 4;
    values->vstring = get_string(tvb, ioffset, values->vvalue);
    proto_tree_add_string(it_tree, hf_mv_string, tvb, ioffset,
                          values->vvalue, values->vstring);
    ioffset += values->vvalue;
    /* end of DCWPutValue */

    ioffset += align_4(tvb, ioffset);

    values->voffset = ioffset;
    return;
}

static void
process_set_filter(proto_tree *it_tree, tvbuff_t *tvb, packet_info *pinfo, nds_val *values)
{
    uint32_t    search_tag, ioffset = values->voffset;
    const char *search_string;

    search_tag = tvb_get_letohl(tvb, ioffset);
    search_string = val_to_str_const(search_tag, itersearchenum, "(No Search Tag Found)");
    proto_tree_add_uint_format(it_tree, hf_iter_search, tvb, ioffset, 4,
        search_tag, "Type of Search: Tag = %d, (0x%04x), %s",
        search_tag, search_tag, search_string);
    ioffset += 4;
    values->voffset = ioffset;

    switch (search_tag)
    {
    case NDS_SEARCH_ITEM:
        /* DCWPutSearchExp */
        process_search_expression(it_tree, tvb, values);
        break;

    case NDS_SEARCH_EXTENSIBLE:
#if 0
        err = DCWPutSearchExtMatch(context, syncFormat, cur, limit, sexp->u.extMatch);
#endif
        process_search_match(it_tree, tvb, values);
        break;

    case NDS_SEARCH_OR:
    case NDS_SEARCH_AND:
    case NDS_SEARCH_NOT:
        /* DCWPutSearchSubExp = process_search_subexpression */
        process_search_subexpression(it_tree, tvb, pinfo, values);
        break;
    default: /* Unknown Iteration search type */
        if (tvb_captured_length_remaining(tvb, ioffset) < 4) {
            THROW(ReportedBoundsError);
        }
        break;
    }
    /*ioffset = values->voffset;*/
    return;
}

/*
 * XXX - what if DSI_OUTPUT_FIELDS *isn't* set in the flags?
 * If so, then there *aren't* any flags in which it *could* be
 * set.
 *
 * This is processing entries in a response to a request that
 * probably contained a list of requested flags; if *that* list
 * doesn't have DSI_OUTPUT_FIELDS set, perhaps we should
 * assume that field isn't present in the response, and that
 * the flags in the request indicate what's in the response.
 *
 * Either that, or report an error with an expert info, and
 * give up on trying to parse the response.
 */
static void
process_entry_info(proto_tree *it_tree, tvbuff_t *tvb, nds_val *values)
{
    uint32_t    iter_flags, ioffset = values->voffset;
    nstime_t    ns;

    values->vstring = NULL;
    ioffset += align_4(tvb, ioffset);
    iter_flags = tvb_get_letohl(tvb, ioffset);


    if (iter_flags & DSI_OUTPUT_FIELDS) { /* Output Flags */
        proto_tree_add_bitmask(it_tree, tvb, ioffset, hf_retinfoflagsl, ett_ncp, ncp_infoflagsl, ENC_LITTLE_ENDIAN);
        ioffset = ioffset+2;
        proto_tree_add_bitmask(it_tree, tvb, ioffset, hf_retinfoflagsh, ett_ncp, ncp_retinfoflagsh, ENC_LITTLE_ENDIAN);
        ioffset = ioffset+2;
    }
    if (iter_flags & DSI_ENTRY_ID) { /* Entry ID */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_eid, tvb, ioffset,
                4, values->vvalue, "Entry ID 0x%08x", values->vvalue);
        ioffset = ioffset + 4;
    }
    if (iter_flags & DSI_ENTRY_FLAGS) { /* Entry Flags */
        proto_tree_add_bitmask(it_tree, tvb, ioffset, hf_eflags, ett_ncp, ncp_eflags, ENC_LITTLE_ENDIAN);
        ioffset = ioffset+4;
    }
    if (iter_flags & DSI_SUBORDINATE_COUNT) { /* Subordinate Count */
        proto_tree_add_item(it_tree, hf_sub_count, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        ioffset += 4;
    }
    if (iter_flags & DSI_MODIFICATION_TIME) { /* Modification Time */
        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
        ns.nsecs = 0;
        proto_tree_add_time_format(it_tree, hf_es_seconds, tvb, ioffset,
                4, &ns, "Modification Time: %s",
                abs_time_secs_to_str(wmem_packet_scope(), ns.secs, ABSOLUTE_TIME_LOCAL, true));
        ioffset = ioffset + 4;
    }
    if (iter_flags & DSI_MODIFICATION_TIMESTAMP) { /* Modification Timestamp */
        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
        ns.nsecs = 0;
        proto_tree_add_time_format(it_tree, hf_es_seconds, tvb, ioffset,
                4, &ns, "Modification Timestamp: %s",
                abs_time_secs_to_str(wmem_packet_scope(), ns.secs, ABSOLUTE_TIME_LOCAL, true));
        ioffset = ioffset + 4;
        proto_tree_add_item(it_tree, hf_nds_replica_num, tvb, ioffset,
                2, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 2;
        proto_tree_add_item(it_tree, hf_nds_event_num, tvb, ioffset,
                2, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 2;
    }
    if (iter_flags & DSI_CREATION_TIMESTAMP) { /* Creation Timestamp */
        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
        ns.nsecs = 0;
        proto_tree_add_time_format(it_tree, hf_es_seconds, tvb, ioffset,
                4, &ns, "Creation Timestamp: %s",
                abs_time_secs_to_str(wmem_packet_scope(), ns.secs, ABSOLUTE_TIME_LOCAL, true));
        ioffset = ioffset + 4;
        proto_tree_add_item(it_tree, hf_nds_replica_num, tvb, ioffset,
                2, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 2;
        proto_tree_add_item(it_tree, hf_nds_event_num, tvb, ioffset,
                2, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 2;
    }
    if (iter_flags & DSI_PARTITION_ROOT_ID) { /* Partition Root ID */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_local_partition, tvb, ioffset,
                4, values->vvalue, "Partition Root ID %08x", values->vvalue);
        ioffset = ioffset + 4;
    }
    if (iter_flags & DSI_PARENT_ID) { /* Parent ID */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_local_partition, tvb, ioffset,
                4, values->vvalue, "Parent ID %08x", values->vvalue);
        ioffset = ioffset + 4;
    }
    if (iter_flags & DSI_REVISION_COUNT) { /* Revision Count */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_local_partition, tvb, ioffset,
                4, values->vvalue, "Revision count %08x", values->vvalue);
        ioffset = ioffset + 4;
    }
    if (iter_flags & DSI_REPLICA_TYPE) { /* Replica Type */
        values->vvalue = tvb_get_letohl(tvb, ioffset) & 0x00ff;
        proto_tree_add_uint(it_tree, hf_replica_type, tvb, ioffset, 4, values->vvalue);
        values->vvalue = tvb_get_letohl(tvb, ioffset) & 0xff00;
        proto_tree_add_uint(it_tree, hf_replica_state, tvb, ioffset, 4, values->vvalue);
        ioffset = ioffset + 4;
    }
    if (iter_flags & DSI_BASE_CLASS) { /* Base Class */
        values->vvalue = tvb_get_letohl(tvb, ioffset);         /* Length of string */
        ioffset = ioffset+4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string_format(it_tree, hf_value_string, tvb, ioffset,
                values->vvalue, values->vstring,
                "Base Class: - %s", values->vstring);
        ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
        ioffset += align_4(tvb, ioffset);
    }
    if (iter_flags & DSI_ENTRY_RDN) { /* Relative Distinguished Name */
        values->vvalue = tvb_get_letohl(tvb, ioffset);         /* Length of string */
        ioffset = ioffset+4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string_format(it_tree, hf_value_string, tvb, ioffset,
                 values->vvalue, values->vstring,
                 "Relative Distinguished Name - %s", values->vstring);
        ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
        ioffset += align_4(tvb, ioffset);
    }
    if (iter_flags & DSI_ENTRY_DN) { /* Distinguished Name */
        values->vvalue = tvb_get_letohl(tvb, ioffset);         /* Length of string */
        ioffset = ioffset+4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string_format(it_tree, hf_value_string, tvb, ioffset,
                 values->vvalue, values->vstring,
                 "Distinguished Name - %s", values->vstring);
        ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
        ioffset += align_4(tvb, ioffset);
    }
    if (iter_flags & DSI_PARTITION_ROOT_DN) { /* Root Distinguished Name */
        values->vvalue = tvb_get_letohl(tvb, ioffset);         /* Length of string */
        ioffset = ioffset+4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string_format(it_tree, hf_value_string, tvb, ioffset,
                 values->vvalue, values->vstring,
                 "Root Distinguished Name - %s", values->vstring);
        ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
        ioffset += align_4(tvb, ioffset);
    }
    if (iter_flags & DSI_PARENT_DN) { /* Parent Distinguished Name */
        values->vvalue = tvb_get_letohl(tvb, ioffset);         /* Length of string */
        ioffset = ioffset+4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string_format(it_tree, hf_value_string, tvb, ioffset,
                 values->vvalue, values->vstring,
                 "Parent Distinguished Name - %s", values->vstring);
        ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
        ioffset += align_4(tvb, ioffset);
    }
    if (iter_flags & DSI_PURGE_TIME) { /* Purge Time */
        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
        ns.nsecs = 0;
        proto_tree_add_time(it_tree, hf_nds_purge, tvb, ioffset, 4, &ns);
        ioffset = ioffset + 4;
    }
    if (iter_flags & DSI_DEREFERENCED_BASE_CLASS) { /* Dereference Base Class */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        ioffset = ioffset + 4;
        values->vstring = get_string(tvb, ioffset, values->vvalue);
        proto_tree_add_string(it_tree, hf_deref_base, tvb, ioffset,
                values->vvalue, values->vstring);
        ioffset = check_offset_addition(ioffset, values->vvalue, it_tree, NULL, tvb);
    }
    if (iter_flags & DSI_REPLICA_NUMBER) { /* Replica Number */
        proto_tree_add_item_ret_uint(it_tree, hf_replica_number, tvb, ioffset,
                 4, ENC_LITTLE_ENDIAN, &values->vvalue);
        ioffset = ioffset+4;
    }
    if (iter_flags & DSI_REPLICA_STATE) { /* Replica State */
        values->vvalue = tvb_get_letohl(tvb, ioffset) & 0xff00;
        values->vstring = val_to_str_const(values->vvalue, nds_replica_state, "No Replica State Found");
        proto_tree_add_uint(it_tree, hf_replica_state, tvb, ioffset, 4, values->vvalue);
        ioffset = ioffset + 2;
    }
    if (iter_flags & DSI_FEDERATION_BOUNDARY) { /* Federation Boundary */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_uint32value, tvb, ioffset,
                4, values->vvalue, "Federation Boundary %d", values->vvalue);
        ioffset = ioffset+4;
    }
    if (iter_flags & DSI_SCHEMA_BOUNDARY) { /* Schema Boundary */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_uint32value, tvb, ioffset,
                4, values->vvalue, "Schema Boundary %d", values->vvalue);
        ioffset = ioffset+4;
    }
    if (iter_flags & DSI_FEDERATION_BOUNDARY_ID) { /* Federation Boundary ID */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_uint32value, tvb, ioffset,
                4, values->vvalue, "Federation Boundary ID %d", values->vvalue);
        ioffset = ioffset+4;
    }
    if (iter_flags & DSI_SCHEMA_BOUNDARY_ID) { /* Schema Boundary ID*/
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_uint32value, tvb, ioffset,
                4, values->vvalue, "Schema Boundary ID %d", values->vvalue);
        ioffset = ioffset+4;
    }
    if (iter_flags & DSI_CUR_SUBCOUNT) { /* Current Subcount */
        values->vvalue = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_uint_format(it_tree, hf_nds_uint32value, tvb, ioffset,
                4, values->vvalue, "Current Subcount %d", values->vvalue);
        ioffset = ioffset+4;
    }
    if (iter_flags & DSI_LOCAL_ENTRY_FLAGS) { /* Local Entry Flags */
        proto_tree_add_bitmask(it_tree, tvb, ioffset, hf_eflags, ett_ncp, ncp_eflags, ENC_LITTLE_ENDIAN);
        ioffset = ioffset+4;
    }
    values->voffset = ioffset;
    return;
}

static void
dissect_nds_iterator(proto_tree *it_tree, tvbuff_t *tvb, packet_info *pinfo, uint32_t it_verb, uint32_t request_flags, uint32_t ioffset, bool request_reply)
{
    uint32_t    rcode, i, number_of_items, number_to_get;
    const char  *error_string;
    nds_val     values;
    proto_tree  *it_subtree, *it_subtree1;
    proto_item  *it_subitem;
    proto_item  *expert_item;

    values.vtype = 0;
    values.vvalue = 0;
    values.vlength = 0;
    values.voffset = 0;
    values.hfname = 0;
    values.vdesc = "";
    values.vstring = NULL;
    values.mvtype = 0;
    values.vflags = 0;


    while (true) {
        it_subitem = proto_tree_add_uint(it_tree, hf_ncp_nds_iterverb, tvb, ioffset-4, 4, it_verb);

        it_subtree = proto_item_add_subtree(it_subitem, ett_nds);

        if (request_reply) { /* Request packets */
            switch (it_verb) {
            case IT_ATFIRST:
            case IT_ATEOF:
            case IT_ATLAST:
            case IT_ATBOF:
            case IT_CLEAR:
            case IT_COPY:
                break;
            case IT_COUNT:
                proto_tree_add_item(it_subtree, hf_timelimit, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                proto_tree_add_item(it_subtree, hf_max_entries, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                proto_tree_add_item(it_subtree, hf_move_position, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_CREATE:
            case IT_CURRENT:
            case IT_DESTROY:
            case IT_DONE:
                break;
            case IT_FIRST:
                proto_tree_add_item(it_subtree, hf_timelimit, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_GETPOSITION:
            case IT_ISPOSITIONABLE:
                break;
            case IT_LAST:
                proto_tree_add_item(it_subtree, hf_timelimit, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_NEXT:
            case IT_PREV:
                proto_tree_add_item(it_subtree, hf_timelimit, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                proto_tree_add_item(it_subtree, hf_num_to_get, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_POSITION:
                proto_tree_add_item(it_subtree, hf_iter_position, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                proto_tree_add_item(it_subtree, hf_timelimit, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_POSITION_IT:
                proto_tree_add_item(it_subtree, hf_iter_other, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_SETINDEX:
                proto_tree_add_item(it_subtree, hf_nds_number_of_items, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                number_of_items = tvb_get_letohl(tvb, ioffset);
                ioffset += 4;
                for (i=0; i < number_of_items; i++) {
                    /* Process the attribute tag */
#if 0
                    proto_tree_add_item(it_subtree, hf_nds_tag_string, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
#endif
                    proto_tree_add_item(it_subtree, hf_iter_index, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 4;

                    /* start of DCWPutAttribute */
#if 0
                    values.vvalue = tvb_get_letohl(tvb, ioffset);
                    ioffset = ioffset + 4;
                    values.vstring = get_string(tvb, ioffset, values.vvalue);
                    proto_tree_add_string(it_subtree, hf_mv_string, tvb, ioffset,
                            values.vvalue, values.vstring);
                    ioffset = check_offset_addition(ioffset, values.vvalue, it_subtree, pinfo, tvb);
#endif
                    /* end of DCWPutAttribute */

#if 0
                    ioffset += align_4(tvb, ioffset);
#endif
                    if (tvb_captured_length_remaining(tvb, ioffset) < 4) {
                        THROW(ReportedBoundsError);
                        return;
                    }
                }
                break;
            case IT_SETFILTER:

                values.voffset = ioffset;

                /* DCWPutSearchExp  = process_set_filter() */
                process_set_filter(it_subtree, tvb, pinfo, &values);

                ioffset = values.voffset;
                ioffset += align_4(tvb, ioffset);
                break;
            case IT_SKIP:
                proto_tree_add_item(it_subtree, hf_timelimit, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                proto_tree_add_item(it_subtree, hf_num_to_skip, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_TYPEDOWN:
                proto_tree_add_item(it_subtree, hf_num_to_get, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                number_to_get = tvb_get_letohl(tvb, ioffset);
                ioffset += 4;
                if (number_to_get == 0) {
                    proto_tree_add_item(it_tree, hf_nds_tag_string, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 4;

                }
                values.vvalue = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset + 4;
                values.vstring = get_string(tvb, ioffset, values.vvalue);
                proto_tree_add_string(it_subtree, hf_mv_string, tvb, ioffset,
                        values.vvalue, values.vstring);
                ioffset = check_offset_addition(ioffset, values.vvalue, it_subtree, pinfo, tvb);
                ioffset += align_4(tvb, ioffset);
                break;
            default:
                if (tvb_captured_length_remaining(tvb, ioffset) < 4) {
                    THROW(ReportedBoundsError);
                }
                return;
            }
        }
        else    /* Reply Packets */
        {                                           /* All replies include a completion code first */
            expert_item = proto_tree_add_item_ret_uint(it_subtree, hf_iter_verb_completion_code, tvb, ioffset,
                    4, ENC_LITTLE_ENDIAN, &rcode);
            error_string = val_to_str_const(rcode, nds_reply_errors, "Unknown Interation Verb Completion Code");

            if (rcode != 0 && ncp_echo_err) {
                expert_add_info_format(pinfo, expert_item, &ei_iter_verb_completion_code, "Iteration Verb Error: 0x%08x %s", rcode, error_string);
            }
            ioffset += 4;

            switch (it_verb) {
            case IT_ATFIRST:
            case IT_ATEOF:
            case IT_ATLAST:
            case IT_ATBOF:
                proto_tree_add_item(it_subtree, hf_iter_ans, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_CLEAR:
                break;
            case IT_COPY:
                proto_tree_add_item(it_subtree, hf_iter_copy, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_COUNT:
                proto_tree_add_item(it_subtree, hf_this_count, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_CREATE:
                proto_tree_add_item(it_subtree, hf_nds_iterator, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_CURRENT:
            case IT_NEXT:
            case IT_PREV:
            case IT_FIRST:
            case IT_LAST:
                proto_tree_add_item(it_subtree, hf_nds_info_type, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 4;
                proto_tree_add_item(it_subtree, hf_data_size, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                number_of_items = tvb_get_letohl(tvb, ioffset);
                proto_tree_add_item(it_subtree, hf_this_count, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                for (i = 0; i < number_of_items; i++)
                {
                    it_subtree1 = proto_tree_add_subtree_format(it_subtree, tvb, ioffset, -1, ett_nds, NULL, "Item #: %u", i+1);

                    ioffset += align_4(tvb, ioffset);

                    /* Start WGetAndBufferEntryInfo = process_entry_info() */
                    values.voffset = ioffset;
                    /*
                     * XXX - each entry also may contain a set of flags
                     * indicating what values are(?) present; which
                     * should be used?
                     */
                    values.vflags = request_flags;
                    process_entry_info(it_subtree1, tvb, &values);
                    ioffset = values.voffset;
                    /* End WGetAndBufferEntryInfo */

                    ioffset += align_4(tvb, ioffset);

                    /* WGetReadBuffer - This seems to be a count and then size field (2 * uint32_t) */
                    /* For now we will just skip this offset. NEED TO ADD LOGIC TO HANDLE */
                    ioffset += 8;

                    if (tvb_captured_length_remaining(tvb, ioffset) < 4) {
                        break;
                    }
                }
                break;
            case IT_DESTROY:
            case IT_DONE:
                break;
            case IT_GETPOSITION:
                proto_tree_add_item(it_subtree, hf_iter_position, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_ISPOSITIONABLE:
                proto_tree_add_item(it_subtree, hf_positionable, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_POSITION:
            case IT_POSITION_IT:
            case IT_SETFILTER:
            case IT_TYPEDOWN:
                break;
            case IT_SETINDEX:
                proto_tree_add_item(it_subtree, hf_iter_index, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            case IT_SKIP:
                proto_tree_add_item(it_subtree, hf_num_skipped, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset += 4;
                break;
            default:
                if (tvb_captured_length_remaining(tvb, ioffset) < 4) {
                    THROW(ReportedBoundsError);
                }
                return;
            }
        }
        it_verb = tvb_get_letohl(tvb, ioffset);
        ioffset += 4;
        if (it_verb == IT_DONE || tvb_captured_length_remaining(tvb, ioffset) < 4) {
            proto_tree_add_uint(it_tree, hf_ncp_nds_iterverb, tvb, ioffset-4, 4, it_verb);
            break;
        }
    }
    return;
}


static void
process_multivalues(proto_tree *ncp_tree, tvbuff_t *tvb, packet_info *pinfo, nds_val *values)
{
    uint32_t        i;
    uint32_t        r;
    uint32_t        ioffset = 0, oldioffset;
    uint32_t        value1 = 0;
    uint32_t        value2 = 0;
    uint8_t         value3 = 0;
    uint32_t        value4 = 0;
    int             value5 = 0;
    uint32_t        value6 = 0;
    uint32_t        value7 = 0;
    const char      *valuestr = "";
    proto_tree      *ntree;
    proto_tree      *atree;
    proto_item      *nitem;
    proto_item      *aitem;
    uint32_t        number_of_referrals = 0;
    proto_tree      *estree;
    proto_item      *esitem;
    uint32_t        bvalue=0;
    nds_val         temp_values;
    proto_tree      *sub1tree;
    proto_item      *sub1item;
    proto_tree      *sub2tree;
    proto_item      *sub2item;
    int             length_remaining;
    nstime_t        ns;

    mv_resolve_name_string[0] = '\0';
    values->vstring = "";

    /* Is the value passed a string or UINT32? */
    /* XXX - this should just be an FT_NONE to cover the entire item */
    if(values->mvtype != MVTYPE_LIST_PARTITIONS && values->mvtype != MVTYPE_PROCESS_TAGS)
    {
        nitem = proto_tree_add_uint_format(ncp_tree, values->hfname, tvb, values->voffset+ioffset,
                                           values->vlength, values->vvalue, values->vdesc, values->vvalue);
    }
    else
    {
        nitem = proto_tree_add_string_format(ncp_tree, values->hfname, tvb, values->voffset+ioffset,
                                             values->vlength, values->vdesc, "%s", values->vdesc);
    }
    ioffset = (values->voffset+4);

    ntree = proto_item_add_subtree(nitem, ett_nds);

    switch (values->mvtype)
    {
    case MVTYPE_ATTR_REQUEST:   /* Attribute Request */
        for (i = 1 ; i <= values->vvalue; i++ )
        {
            ioffset += align_4(tvb, ioffset);
            value1 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value1);
            proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                  value1, values->vstring);
            ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
        }
        break;

    case MVTYPE_ATTR_REPLY:     /* Attribute Reply */
        switch(values->vflags)
        {
        case 0:
            for (i = 1 ; i <= values->vvalue; i++ )
            {
                ioffset += align_4(tvb, ioffset);
                value1 = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset + 4;
                values->vstring = get_string(tvb, ioffset, value1);
                proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                      value1, values->vstring);
                ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
            }
            break;
        case 1:
            for (i = 1 ; i <= values->vvalue; i++ )
            {
                uint32_t syntax;

                proto_tree_add_item_ret_uint(ntree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN, &syntax);
                ioffset = ioffset + 4;
                value2 = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset + 4;
                values->vstring = get_string(tvb, ioffset, value2);
                proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                      value2, values->vstring);
                ioffset += value2;
                ioffset += align_4(tvb, ioffset);
                values->voffset = ioffset;

                print_nds_values(ntree, pinfo, tvb, syntax, values);
                ioffset = values->voffset;
            }
            break;
        case 2:
            for (i = 1 ; i <= values->vvalue; i++ )
            {
                proto_tree_add_item(ntree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 4;
                value2 = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset + 4;
                values->vstring = get_string(tvb, ioffset, value2);
                proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                      value2, values->vstring);
                values->voffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
                ioffset += value2;
                ioffset += align_4(tvb, ioffset);
                value3 = tvb_get_letohl(tvb, ioffset);

                proto_tree_add_uint_format(ntree, hf_nds_uint32value, tvb, ioffset, 4,
                                           value3, "Number of Values - %u", value3);

                ioffset = ioffset + 4;
                for (r = 1 ; r <= value3; r++ )
                {
                    ioffset += 4;   /* Length = 4 */
                    proto_tree_add_item(ntree, hf_nds_privileges, tvb, ioffset,
                                        values->vlength, ENC_LITTLE_ENDIAN);

                    ioffset = ioffset+4;
                }
            }
            break;
        case 3:
            for (i = 1 ; i <= values->vvalue; i++ )
            {
                proto_tree_add_item(ntree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 4;
                value2 = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset + 4;
                values->vstring = get_string(tvb, ioffset, value2);
                proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                      value2, values->vstring);
                ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
                ioffset += align_4(tvb, ioffset);
                value3 = tvb_get_letohl(tvb, ioffset);

                aitem = proto_tree_add_uint_format(ntree, hf_nds_uint32value, tvb, ioffset, 4,
                                                   value3, "Number of Values - %u", value3);

                atree = proto_item_add_subtree(aitem, ett_nds);

                ioffset = ioffset + 4;
                for (r = 1 ; r <= value3; r++ )
                {
                    ioffset += align_4(tvb, ioffset);
                    proto_tree_add_bitmask(atree, tvb, ioffset, hf_vflags, ett_ncp, ncp_vflags, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 4;
                    ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                    ns.nsecs = 0;
                    proto_tree_add_time_format(atree, hf_es_seconds, tvb, ioffset,
                                               4, &ns, "Timestamp: %s",
                                               abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                    ioffset = ioffset + 4;
                    proto_tree_add_item(atree, hf_nds_replica_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    proto_tree_add_item(atree, hf_nds_event_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    value5 = tvb_get_letohl(tvb, ioffset); /* length of field */
                    if(value5 > tvb_captured_length_remaining(tvb, ioffset))
                    {
                        break;
                    }
                    ioffset += 4;
                    proto_tree_add_item(atree, hf_value_bytes, tvb, ioffset, value5, ENC_NA);
                    ioffset += value5;
                    ioffset += (value5%2);
                }
            }
            break;
        case 4:
            for (i = 1 ; i <= values->vvalue; i++ )
            {
                proto_tree_add_item(ntree, hf_nds_syntax, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 4;
                value2 = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset + 4;
                values->vstring = get_string(tvb, ioffset, value2);
                proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                      value2, values->vstring);
                ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
                value3 = tvb_get_letohl(tvb, ioffset);

                proto_tree_add_uint_format(ntree, hf_nds_uint32value, tvb, ioffset, 4,
                                           value3, "Number of Values - %u", value3);

                ioffset = ioffset + 4;
                for (r = 1 ; r <= value3; r++ )
                {
                    ioffset += align_4(tvb, ioffset);
                    proto_tree_add_bitmask(ntree, tvb, ioffset, hf_vflags, ett_ncp, ncp_vflags, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 4;
                    ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                    ns.nsecs = 0;
                    proto_tree_add_time_format(ntree, hf_es_seconds, tvb, ioffset,
                                               4, &ns, "Creation Time: %s",
                                               abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                    ioffset = ioffset + 4;
                    proto_tree_add_item(ntree, hf_nds_replica_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    proto_tree_add_item(ntree, hf_nds_event_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    proto_tree_add_item(ntree, hf_nds_value_len, tvb, ioffset,
                                        4, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 4;
                }
            }
            break;
        default:
            break;
        }
        break;

    case MVTYPE_ATTR_REQUEST2:    /* Attribute Request */
        oldioffset = 0;
        for (i = 1 ; i <= values->vvalue; i++ )
        {
            if (oldioffset >= ioffset) {
                proto_tree_add_expert_format(ntree, pinfo, &ei_ncp_invalid_offset, tvb, 0, 0, "Invalid offset: %u", ioffset);
                THROW(ReportedBoundsError);
            }
            oldioffset = ioffset;
            ioffset += align_4(tvb, ioffset);
            value1 = tvb_get_letohl(tvb, ioffset);
            proto_tree_add_uint_format(ntree, hf_nds_uint32value, tvb, ioffset,
                                       4, value1, "Value %d", value1);
            ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
        }
        break;

    case MVTYPE_ADD_ATTR_REQUEST: /* Add Attribute Request */
        for (i = 1 ; i <= values->vvalue; i++ )
        {
            value1 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value1);
            proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                  value1, values->vstring);
            ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
            values->voffset = ioffset;
            print_nds_values(ntree, pinfo, tvb, 9, values);
            ioffset = values->voffset;
        }
        break;

    case MVTYPE_READ_CLASS_REQ:   /* Read Class Request */
        for (i = 1 ; i <= values->vvalue; i++ )
        {
            ioffset += align_4(tvb, ioffset);
            value1 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value1);
            proto_tree_add_string(ntree, hf_nds_base, tvb, ioffset,
                                  value1, values->vstring);
            values->mvtype = MVTYPE_ATTR_REQUEST;
            ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
        }
        break;

    case MVTYPE_READ_REPLICAS:    /* Read Replicas */
        for (i = 1 ; i <= values->vvalue; i++ )
        {
            bvalue = 0x00000001;

            for (r = 0 ; r < 9; r++ )
            {
                if (values->vflags & bvalue)
                {
                    // Note: these do not all apear to be DSI_ flags
                    switch(bvalue)
                    {
                    case 0x00000001:                /*p3values.bit1 = "Output Flags"*/
                        proto_tree_add_bitmask(ntree, tvb, ioffset, hf_outflags, ett_ncp, ncp_outflags, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 4;
                        break;
                    case 0x00000002:                /*p3values.bit2 = "Entry ID"*/
                        value1 = tvb_get_letohl(tvb, ioffset);
                        proto_tree_add_uint_format(ntree, hf_nds_eid, tvb, ioffset,
                                                   4, value1, "Entry ID %08x", value1);
                        ioffset = ioffset + 4;
                        break;
                    case 0x00000004:                /*p3values.bit3 = "Replica State"*/
                        proto_tree_add_item_ret_uint(ntree, hf_replica_state, tvb, ioffset,
                                              4, ENC_LITTLE_ENDIAN, &value1);
                        ioffset = ioffset + 4;
                        break;
                    case 0x0000008:                 /*p3values.bit4 = "Modification Timestamp"*/
                        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                        ns.nsecs = 0;
                        proto_tree_add_time_format(ntree, hf_es_seconds, tvb, ioffset,
                                                   4, &ns, "Modification Timestamp: %s",
                                                   abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                        ioffset = ioffset + 4;
                        proto_tree_add_item(ntree, hf_nds_replica_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        proto_tree_add_item(ntree, hf_nds_event_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        break;
                    case 0x00000010:                /*p3values.bit5 = "Purge Time"*/
                        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                        ns.nsecs = 0;
                        proto_tree_add_time(ntree, hf_nds_purge, tvb, ioffset, 4, &ns);
                        ioffset = ioffset + 4;
                        break;
                    case 0x00000020:                /*p3values.bit6 = "Local Partition ID"*/
                        proto_tree_add_item(ntree, hf_nds_local_partition, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 4;
                        break;
                    case 0x00000040:                /*p3values.bit7 = "Distinguished Name"*/
                        value1 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value1);
                        proto_tree_add_string(ntree, hf_nds_name, tvb, ioffset,
                                              value1, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
                        break;
                    case 0x00000080:                /*p3values.bit8 = "Replica Type & State"*/
                        value1 = tvb_get_letohl(tvb, ioffset);
                        value2 = value1 & 0x00ff;
                        proto_tree_add_uint(ntree, hf_replica_type, tvb, ioffset, 4, value2);
                        value3 = value1 & 0xff00;
                        proto_tree_add_uint(ntree, hf_replica_state, tvb, ioffset, 4, value3);
                        ioffset = ioffset + 4;
                        break;
                    case 0x00000100:                /*p3values.bit9 = "Partition Busy"*/
                        value1 = tvb_get_letohs(tvb, ioffset);
                        proto_tree_add_boolean(ntree, hf_partition_busy, tvb, ioffset, 4, value1);
                        ioffset += 4;
                        break;
                    default:
                        break;
                    }
                }
                bvalue = bvalue*2;
                ioffset += align_4(tvb, ioffset);
                if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
                {
                    break;
                }
            }
            if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
            {
                break;
            }
        }
        break;

    case MVTYPE_MODIFY_ATTR_REQUEST: /* Modify Attribute Request */
        for (i = 0 ; i < values->vvalue; i++ )
        {
            ioffset += align_4(tvb, ioffset);
            value1 = tvb_get_letohl(tvb, ioffset);
            valuestr = val_to_str_const(value1, nds_kind_of_changes, "(Kind Change Not Found)");
            proto_tree_add_uint_format(ntree, hf_nds_uint32value, tvb, ioffset,
                                       values->vlength, value1, valuestr, value1);
            ioffset = ioffset+4;
            value2 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            temp_values.vstring = get_string(tvb, ioffset, value2);   /* Name of Attribute */
            proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                  value2, temp_values.vstring);
            ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
            if(value1 != 1 && value1 != 6)
            {
                values->voffset = ioffset;
                /* XX: Is values.vstring set properly at this point ?? */
                print_nds_values(ntree, pinfo, tvb, 9, values);
                ioffset = values->voffset;
            }
        }
        break;

    case MVTYPE_ADDR_REFERRAL_REQUEST: /* Address Referral Request */
        for (i = 0 ; i < values->vvalue; i++ )
        {
            value1 = tvb_get_letohl(tvb, ioffset);
            valuestr = val_to_str_const(value1, nds_protocol_type, "(Undefined Protocol)");
            proto_tree_add_uint_format(ntree, hf_nds_uint32value, tvb, ioffset,
                                       values->vlength, value1, valuestr, value1);
            ioffset = ioffset+4;
        }
        break;

    case MVTYPE_ADDR_REFERRAL_REPLY: /* Address Referral Reply */
        number_of_referrals = values->vvalue;

        for (r = 1 ; r <= number_of_referrals; r++ )
        {
            aitem = proto_tree_add_uint_format(ntree, hf_referral_record, tvb, 6, 0,
                                               r, "NDS Referral Record #%u", r);
            atree = proto_item_add_subtree(aitem, ett_nds);

            proto_tree_add_item_ret_uint(atree, hf_referral_addcount, tvb, ioffset, 4, ENC_LITTLE_ENDIAN, &value1);

            ioffset = ioffset + 4;
            for (i = 1 ; i <= value1; i++ )
            {
                value2 = tvb_get_letohl(tvb, ioffset);
                valuestr = val_to_str_const(value2, nds_protocol_type, "(Undefined Protocol)");
                proto_tree_add_uint_format(atree, hf_nds_uint32value, tvb, ioffset,
                                           values->vlength, value2, valuestr, value2);
                ioffset = ioffset+4;
                value3 = tvb_get_letohl(tvb, ioffset);
                ioffset = ioffset+4;
                switch (value2)
                {
                case NDS_PTYPE_IPX:
                    proto_tree_add_item(atree, hf_nds_net, tvb, ioffset, 4, ENC_BIG_ENDIAN);
                    proto_tree_add_item(atree, hf_nds_node, tvb, ioffset+4, 6, ENC_NA);
                    proto_tree_add_item(atree, hf_nds_socket, tvb, ioffset+10, 2, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_IP:
                    proto_tree_add_item(atree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(atree, hf_add_ref_ip, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_UDP:
                    proto_tree_add_item(atree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(atree, hf_add_ref_udp, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_TCP:
                    proto_tree_add_item(atree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                    proto_tree_add_item(atree, hf_add_ref_tcp, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                    break;
                case NDS_PTYPE_URL:
                case NDS_PTYPE_DNS:
                    values->vstring = get_string(tvb, ioffset, value3);
                    proto_tree_add_string(atree, hf_value_string, tvb, ioffset,
                                          value3, values->vstring);
                    break;
                default:
                    break;
                }
                ioffset = check_offset_addition(ioffset, value3, atree, pinfo, tvb);
                ioffset += align_4(tvb, ioffset);
            }

        }
        break;

    case MVTYPE_LOC_ADDR_REFERRAL_REPLY: /* Local Address Referral Reply */
        number_of_referrals = values->vvalue;

        for (r = 1 ; r <= number_of_referrals; r++ )
        {
            aitem = proto_tree_add_uint_format(ntree, hf_referral_record, tvb, 6, 0,
                                               r, "NDS Referral Record #%u", r);
            atree = proto_item_add_subtree(aitem, ett_nds);

            value2 = tvb_get_letohl(tvb, ioffset);
            valuestr = val_to_str_const(value2, nds_protocol_type, "(Undefined Protocol)");
            proto_tree_add_uint_format(atree, hf_nds_uint32value, tvb, ioffset,
                                       values->vlength, value2, valuestr, value2);
            ioffset = ioffset+4;
            value3 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset+4;

            switch (value2)
            {
            case NDS_PTYPE_IPX:
                proto_tree_add_item(atree, hf_nds_net, tvb, ioffset, 4, ENC_BIG_ENDIAN);
                proto_tree_add_item(atree, hf_nds_node, tvb, ioffset+4, 6, ENC_NA);
                proto_tree_add_item(atree, hf_nds_socket, tvb, ioffset+10, 2, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_IP:
                proto_tree_add_item(atree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(atree, hf_add_ref_ip, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_UDP:
                proto_tree_add_item(atree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(atree, hf_add_ref_udp, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_TCP:
                proto_tree_add_item(atree, hf_nds_port, tvb, ioffset, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(atree, hf_add_ref_tcp, tvb, ioffset+2, 4, ENC_BIG_ENDIAN);
                break;
            case NDS_PTYPE_URL:
            case NDS_PTYPE_DNS:
                values->vstring = get_string(tvb, ioffset, value3);
                proto_tree_add_string(atree, hf_value_string, tvb, ioffset,
                                      value3, values->vstring);
                break;
            default:
                break;
            }
            ioffset = check_offset_addition(ioffset, value3, atree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
        }
        break;

    case MVTYPE_PROC_ENTRY_SPECIFIERS: /* Process Entry Specifiers */
        value2 = tvb_get_letohl(tvb, ioffset);   /* ES Type */
        values->vstring = val_to_str_const(value2, es_type, "No ES Type Found");
        esitem = proto_tree_add_string_format(ntree, hf_es_type, tvb, ioffset,
                                              4, values->vstring, "Output Entry Specifier - %s", values->vstring);
        estree = proto_item_add_subtree(esitem, ett_nds);
        ioffset = ioffset + 4;
        ioffset = print_es_type(estree, tvb, values, value2, ioffset);
        value3 = tvb_get_letohl(tvb, ioffset);   /* ES Type */
        values->vstring = val_to_str_const(value3, es_type, "No ES Type Found");
        esitem = proto_tree_add_string_format(ntree, hf_es_type, tvb, ioffset,
                                              4, values->vstring, "Input Entry Specifier - %s", values->vstring);
        estree = proto_item_add_subtree(esitem, ett_nds);
        ioffset = ioffset + 4;
        ioffset = print_es_type(estree, tvb, values, value3, ioffset);
        /* values.vstring is being overwritten. So store the resolve name to a global value */
        (void) g_strlcpy(mv_resolve_name_string, values->vstring, 128);
        value4 = tvb_get_letohl(tvb, ioffset);
        aitem = proto_tree_add_uint_format(ntree, hf_referral_record, tvb, ioffset, 4,
                                           value4, "Referral Protocols - %u", value4);
        atree = proto_item_add_subtree(aitem, ett_nds);
        ioffset += 4;
        for (i = 0 ; i < value4; i++ )
        {
            value5 = tvb_get_letohl(tvb, ioffset);
            valuestr = val_to_str_const(value5, nds_protocol_type, "(Undefined Protocol)");
            proto_tree_add_string_format(atree, hf_value_string, tvb, ioffset,
                                         4, valuestr, "Protocol -> %s", valuestr);
            ioffset = ioffset+4;
        }
        value6 = tvb_get_letohl(tvb, ioffset);
        aitem = proto_tree_add_uint_format(ntree, hf_referral_record, tvb, ioffset, 4,
                                           value6, "Tree Walking Protocols - %u", value6);
        atree = proto_item_add_subtree(aitem, ett_nds);
        ioffset += 4;
        for (i = 0 ; i < value6; i++ )
        {
            value7 = tvb_get_letohl(tvb, ioffset);
            valuestr = val_to_str_const(value7, nds_protocol_type, "(Undefined Protocol)");
            proto_tree_add_string_format(atree, hf_value_string, tvb, ioffset,
                                         4, valuestr, "Protocol -> %s", valuestr);
            ioffset = ioffset+4;
        }
        values->vstring = " ";
        break;

    case MVTYPE_PRINT_TIMESTAMP:  /* Print Timestamp */
        proto_tree_add_item(ncp_tree, hf_nds_replica_num, tvb, ioffset,
                            2, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 2;
        proto_tree_add_item(ncp_tree, hf_nds_event_num, tvb, ioffset,
                            2, ENC_LITTLE_ENDIAN);
        ioffset = ioffset + 2;
        /* fall through */

    case MVTYPE_LIST_PARTITIONS:  /* List Partitions */
        number_of_referrals = values->vvalue;
        /* A bad packet could put us in a tight loop so trap for anything
         * over 256 referrals.
         */
        if (number_of_referrals > 256) {
            proto_tree_add_expert_format(ntree, pinfo, &ei_ncp_invalid_offset, tvb, 0, 0, "Bad referral at offset: %u", ioffset);
            THROW(ReportedBoundsError);
            break;
        }
        for (i = 0; i < number_of_referrals; i++)
        {
            /*
             * XXX - should we just call process_entry_info() here?
             */
            bvalue = 0x00000001;

            /*
             * If the caller didn't request DSI_OUTPUT_FIELDS,
             * assume the presence bits aren't present, so we
             * can't fetch them; use the fields the caller
             * requested, instead.
             *
             * XXX - or should we treat that as an error, and report
             * it with an expert info?
             */
            uint32_t output_fields;

            if (values->vflags & DSI_OUTPUT_FIELDS)
                output_fields = tvb_get_letohl(tvb, ioffset);
            else
                output_fields = values->vflags;
            for (r = 0 ; r < 32; r++ )
            {
                /*oldioffset = ioffset;*/
                if (output_fields & bvalue)
                {
                    switch(bvalue)
                    {
                    case DSI_OUTPUT_FIELDS:           /* Information Flags */
                        /*
                         * XXX - if this bit isn't set, report an error,
                         * because if it's not set, the field containing
                         * the bits, including this bit, isn't present!
                         * (Computer bursts into flames at that point.)
                         */
                        proto_tree_add_bitmask(ntree, tvb, ioffset, hf_infoflagsl, ett_ncp, ncp_infoflagsl, ENC_LITTLE_ENDIAN);
                        ioffset += 2;
                        proto_tree_add_bitmask(ntree, tvb, ioffset, hf_infoflagsh, ett_ncp, ncp_infoflagsh, ENC_LITTLE_ENDIAN);
                        ioffset += 2;
                        break;
                    case DSI_ENTRY_ID:                /* Entry ID */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        proto_tree_add_uint_format(ntree, hf_nds_eid, tvb, ioffset,
                                                   4, value1, "Entry ID %08x", value1);
                        ioffset = ioffset + 4;
                        break;
                    case DSI_ENTRY_FLAGS:             /* Entry Flags */
                        proto_tree_add_bitmask(ntree, tvb, ioffset, hf_eflags, ett_ncp, ncp_eflags, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset+4;
                        break;
                    case DSI_SUBORDINATE_COUNT:       /* Subordinate Count */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        proto_tree_add_uint_format(ntree, hf_sub_count, tvb, ioffset,
                                                   4, value1, "Subordinate Count %u", value1);
                        ioffset = ioffset + 4;
                        break;
                    case DSI_MODIFICATION_TIME:       /* Modification Time */
                        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                        ns.nsecs = 0;
                        proto_tree_add_time_format(ntree, hf_es_seconds, tvb, ioffset,
                                                   4, &ns, "Modification Time: %s",
                                                   abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                        ioffset = ioffset + 4;
                        break;
                    case DSI_MODIFICATION_TIMESTAMP:  /* Modification Timestamp */
                        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                        ns.nsecs = 0;
                        proto_tree_add_time_format(ntree, hf_es_seconds, tvb, ioffset,
                                                   4, &ns, "Modification Timestamp: %s",
                                                   abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                        ioffset = ioffset + 4;
                        proto_tree_add_item(ntree, hf_nds_replica_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        proto_tree_add_item(ntree, hf_nds_event_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        break;
                    case DSI_CREATION_TIMESTAMP:      /* Creation Timestamp */
                        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                        ns.nsecs = 0;
                        proto_tree_add_time_format(ntree, hf_es_seconds, tvb, ioffset,
                                                   4, &ns, "Creation Timestamp: %s",
                                                   abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                        ioffset = ioffset + 4;
                        proto_tree_add_item(ntree, hf_nds_replica_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        proto_tree_add_item(ntree, hf_nds_event_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        break;
                    case DSI_PARTITION_ROOT_ID:       /* Partition Root ID */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        proto_tree_add_uint_format(ntree, hf_nds_partition_root_id, tvb, ioffset,
                                                   4, value1, "Partition Root ID %08x", value1);
                        ioffset = ioffset + 4;
                        break;
                    case DSI_PARENT_ID:               /* Parent ID */
                        proto_tree_add_item(ntree, hf_nds_parent, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 4;
                        break;
                    case DSI_REVISION_COUNT:          /* Revision Count */
                        proto_tree_add_item(ntree, hf_nds_revision, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 4;
                        break;
                    case DSI_REPLICA_TYPE:           /* Replica Type & State */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        value2 = value1 & 0x00ff;
                        proto_tree_add_uint(ntree, hf_replica_type, tvb, ioffset, 4, value2);
                        value3 = value1 & 0xff00;
                        proto_tree_add_uint(ntree, hf_replica_state, tvb, ioffset, 4, value3);
                        ioffset = ioffset + 4;
                        break;
                    case DSI_BASE_CLASS:              /* Base Class */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value1);
                        proto_tree_add_string(ntree, hf_nds_base, tvb, ioffset,
                                              value1, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
                        break;
                    case DSI_ENTRY_RDN:               /* Relative Distinguished Name */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value1);
                        proto_tree_add_string(ntree, hf_nds_relative_dn, tvb, ioffset,
                                              value1, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
                        break;
                    case DSI_ENTRY_DN:                /* Distinguished Name */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value1);
                        proto_tree_add_string(ntree, hf_nds_name, tvb, ioffset,
                                              value1, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
                        break;
                    case DSI_PARTITION_ROOT_DN:       /* Root Distinguished Name */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value1);
                        proto_tree_add_string(ntree, hf_nds_name, tvb, ioffset,
                                              value1, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
                        break;
                    case DSI_PARENT_DN:               /* Parent Distinguished Name */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value1);
                        proto_tree_add_string(ntree, hf_nds_name, tvb, ioffset,
                                              value1, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
                        break;
                    case DSI_PURGE_TIME:              /* Purge Time */
                        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                        ns.nsecs = 0;
                        proto_tree_add_time_format(ntree, hf_es_seconds, tvb, ioffset,
                                                   4, &ns, "Purge Time: %s",
                                                   abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                        ioffset = ioffset + 4;
                        break;
                    case DSI_DEREFERENCED_BASE_CLASS: /* Dereference Base Class */
                        value1 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value1);
                        proto_tree_add_string(ntree, hf_deref_base, tvb, ioffset,
                                              value1, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value1, ntree, pinfo, tvb);
                        break;
                    default:
                        break;

                    }
                    ioffset += align_4(tvb, ioffset);
                }
                bvalue = bvalue*2;
                /* We could loop forever so check to see if bvalue has wrapped to 0.
                 * if so then just abort loop.
                 */
                if (bvalue==0) {
                    break;
                }
                if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
                {
                    break;
                }
            }
            if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
            {
                break;
            }
        }
        break;

    case MVTYPE_CLASS_NAMES:      /* Class Names */
        /*
         * Section 5.15 "Information Types for Class Definitions"
         * of Novell eDirectory Core Services says
         *
         *    DS_CLASS_DEF_NAMES     0 Returns only the class names.
         *
         *    DS_CLASS_DEFS          1 Returns class names, class flags,
         *                             and class definitions (super classes,
         *                             containment classes, naming attributes,
         *                             mandatory attributes, and optional
         *                             attributes).
         *
         *    DS_EXPANDED_CLASS_DEFS 2 Returns class names, class flags,
         *                             class definitions, and class
         *                             definitions of the super classes.
         *
         *    DS_INFO_CLASS_DEFS     3 Returns class names, class flags,
         *                             and ASN.1 identifiers.
         *
         *    DS_FULL_CLASS_DEFS     4 Returns class names, class flags,
         *                             class definitions, class definitions
         *                             of the super classes, and default
         *                             ACLs.
         *
         * Some version of the Linux ncpfs appears to define
         * DS_FULL_CLASS_DEFS_AND_TIMESTAMPS as 5.
         *
         * Those appear to be the values from earlier in the packet,
         * passed to us as values->vflags.
         */
        number_of_referrals = values->vvalue;
        for (i = 0; i < number_of_referrals; i++)
        {
            ioffset += align_4(tvb, ioffset);
            value1 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            temp_values.vstring = get_string(tvb, ioffset, value1);
            sub1item = proto_tree_add_string(ntree, hf_nds_base_class, tvb, ioffset,
                                             value1, temp_values.vstring);
            sub1tree = proto_item_add_subtree(sub1item, ett_nds);
            ioffset = check_offset_addition(ioffset, value1, sub1tree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
            if(values->vflags != 0)
            {
                /* Not just the class names; give the class flags. */
                proto_tree_add_bitmask(sub1tree, tvb, ioffset, hf_cflags, ett_ncp, ncp_cflags, ENC_LITTLE_ENDIAN);
                ioffset = ioffset+4;
                if(values->vflags != 5)
                {
                    /*
                     * XXX - where is it stated that all DS_ values other
                     * than 0 and 5 include an ASN.1 ID?  And should it
                     * be displayed as FT_OID?
                     */
                    value1 = tvb_get_letohl(tvb, ioffset); /* length of field */
                    length_remaining = tvb_captured_length_remaining(tvb, ioffset);
                    if(length_remaining == -1 || value1 > (uint32_t) length_remaining)
                    {
                        break;
                    }
                    ioffset += 4;
                    proto_tree_add_item(sub1tree, hf_nds_asn1, tvb, ioffset, value1, ENC_NA);
                    ioffset += value1;
                    ioffset += (value1%2);
                }
                if(values->vflags == 1 || values->vflags == 2 || values->vflags == 4)
                {
                    /*
                     * Everything except DS_INFO_CLASS_DEFS and 5;
                     * What comes next is class definitions, so that's
                     * what we show here.
                     */
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Super Classes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Super Classes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_nds_super, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Containment Classes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Containment Classes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_nds_base_class, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Naming Attributes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Naming Attributes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_mv_string, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Mandatory Attributes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Mandatory Attributes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_mv_string, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Optional Attributes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Optional Attributes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        ioffset += align_4(tvb, ioffset);
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_mv_string, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
                        {
                            break;
                        }
                    }
                }
                if(values->vflags == 4)   /* ACLs */
                {
                    /*
                     * If the NDS documentation is to be believed, this
                     * is DS_FULL_CLASS_DEFS (4), which is the class definitions
                     * done above, class definitions of the super classes
                     * (which we don't seem to be seeing), and default ACLs
                     * (which is as described above, *not* just one 32-bit
                     * number).
                     *
                     * DS_EXPANDED_CLASS_DEFS (2) also has the class
                     * definitions of the super classes.
                     *
                     * Perhaps *neither* of them have the class definitions
                     * of the super classes immediately after the class
                     * definitions, which is why we aren't checking for 2,
                     * but we shouldn't be doing this for 4, either.
                     * (Do the super classes *follow* the ACLs?  Or do
                     * the descriptions of those DS_ values describe
                     * *API* behavior, so that DS_EXPANDED_CLASS_DEFS
                     * including "class definitions of the super classes"
                     * means that the "class definitions" section includes,
                     * for each of the super classes listed in a class's
                     * description, a class definition entry for that
                     * class, i.e. it's an enumeration that returns
                     * not only the requested classes, but all their
                     * super classes, all the way up to the root of
                     * the class hierarchy?  (Note that a single reply
                     * to NDS Read Class Definitions" doesn't necessarily
                     * contain *all* the classes - subsequent reads may
                     * read more of them.)
                     *
                     * XXX - the ACL permission bits are probably described
                     * by section 5.18 "eDirectory Access Control Rights"
                     * of Novell eDirectory Core Services.
                     */
                    value1 = tvb_get_letohl(tvb, ioffset);  /* ACL entries */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "ACL Entries %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_nds_acl_protected_attribute, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);

                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_nds_acl_subject, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);

                        proto_tree_add_item(sub2tree, hf_nds_acl_privileges, tvb, ioffset,
                                            4, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 4;
                    }
                }
                if(values->vflags == 5)   /* Time stamps and Base Class definitions  */
                {
                    /*
                     * XXX - and what's this?  I *do* see time stamps,
                     * followed by a bunch of other stuff, so maybe
                     * it is, in fact, DS_FULL_CLASS_DEFS_AND_TIMESTAMPS.
                     *
                     * But what's the stuff after it?  Is it, in fact,
                     * present in replies?  Or does it again mean
                     * "walk up the class hierarchy", so that the
                     * class hierarchy is linearized, as per the above?
                     *
                     * BTW, is this the universe's way of saying that
                     * maybe this should be divided into a bunch of
                     * subroutines, called from here, rather than
                     * what appears to be a bit of inheritance by
                     * copy and paste?
                     */
                    ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                    ns.nsecs = 0;
                    proto_tree_add_time_format(sub1tree, hf_es_seconds, tvb, ioffset,
                                               4, &ns, "Creation Timestamp: %s",
                                               abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                    ioffset = ioffset + 4;
                    proto_tree_add_item(sub1tree, hf_nds_replica_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    proto_tree_add_item(sub1tree, hf_nds_event_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                    ns.nsecs = 0;
                    proto_tree_add_time_format(sub1tree, hf_es_seconds, tvb, ioffset,
                                               4, &ns, "Modification Timestamp: %s",
                                               abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                    ioffset = ioffset + 4;
                    proto_tree_add_item(sub1tree, hf_nds_replica_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    proto_tree_add_item(sub1tree, hf_nds_event_num, tvb, ioffset,
                                        2, ENC_LITTLE_ENDIAN);
                    ioffset = ioffset + 2;
                    /* Class Definition */
                    /* XXX - is this really there? */
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Super Classes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Super Classes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_nds_super, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Containment Classes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Containment Classes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_nds_base_class, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Naming Attributes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Naming Attributes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_mv_string, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Mandatory Attributes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Mandatory Attributes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_mv_string, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);  /* Optional Attributes */
                    sub2item = proto_tree_add_uint_format(sub1tree, hf_nds_number_of_items, tvb, ioffset,
                                                          4, value1, "Optional Attributes %u", value1);
                    sub2tree = proto_item_add_subtree(sub2item, ett_nds);
                    ioffset = ioffset + 4;
                    for (r = 0; r < value1; r++)
                    {
                        value2 = tvb_get_letohl(tvb, ioffset);
                        ioffset = ioffset + 4;
                        temp_values.vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_mv_string, tvb, ioffset,
                                              value2, temp_values.vstring);
                        ioffset = check_offset_addition(ioffset, value2, sub2tree, pinfo, tvb);
                        ioffset += align_4(tvb, ioffset);
                    }
                    value1 = tvb_get_letohl(tvb, ioffset);    /* Default ACL */
                    proto_tree_add_uint_format(sub1tree, hf_nds_eid, tvb, ioffset,
                                               4, value1, "Default ACL %08x", value1);
                    ioffset = ioffset + 4;
                    if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
                    {
                        break;
                    }
                }
            }
        }
        break;

    case MVTYPE_MODIFY_CLASS:     /* Modify Class */
        for (i = 1 ; i <= values->vvalue; i++ )   /* Attribute Names to add*/
        {
            ioffset += align_4(tvb, ioffset);
            value1 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value1);
            proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                  value1, values->vstring);
            ioffset = ioffset + value1;
        }
        if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
        {
            break;
        }
        ioffset += align_4(tvb, ioffset);
        proto_tree_add_item_ret_uint(ntree, hf_nds_att_del, tvb, ioffset, 4, ENC_LITTLE_ENDIAN, &value1);
        ioffset = ioffset + 4;
        for (i = 1 ; i <= value1; i++ )   /* Attribute Names to delete*/
        {
            ioffset += align_4(tvb, ioffset);
            value2 = tvb_get_letohl(tvb, ioffset);
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                  value2, values->vstring);
            ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
        }
        if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
        {
            break;
        }
        ioffset += align_4(tvb, ioffset);
        proto_tree_add_item_ret_uint(ntree, hf_nds_acl_add, tvb, ioffset, 4, ENC_LITTLE_ENDIAN, &value1);
        ioffset = ioffset + 4;
        for (i = 1 ; i <= value1; i++ )   /* ACL templates to add*/
        {
            ioffset += align_4(tvb, ioffset);
            value2 = tvb_get_letohl(tvb, ioffset);  /* Attribute Name */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string(ntree, hf_nds_attribute_dn, tvb, ioffset,
                                  value2, values->vstring);
            ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
            value2 = tvb_get_letohl(tvb, ioffset);  /* DN of Trustee */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string(ntree, hf_nds_trustee_dn, tvb, ioffset,
                                  value2, values->vstring);
            ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
            proto_tree_add_item(ntree, hf_nds_privileges, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
        }
        if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
        {
            break;
        }
        ioffset += align_4(tvb, ioffset);
        proto_tree_add_item_ret_uint(ntree, hf_nds_acl_del, tvb, ioffset,
                                   4, ENC_LITTLE_ENDIAN, &value1);
        ioffset = ioffset + 4;
        for (i = 1 ; i <= value1; i++ )   /* ACL templates to delete*/
        {
            ioffset += align_4(tvb, ioffset);
            value2 = tvb_get_letohl(tvb, ioffset);  /* Attribute Name */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string(ntree, hf_nds_attribute_dn, tvb, ioffset,
                                  value2, values->vstring);
            ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
            value2 = tvb_get_letohl(tvb, ioffset);  /* DN of Trustee */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value2);
            proto_tree_add_string(ntree, hf_nds_trustee_dn, tvb, ioffset,
                                  value2, values->vstring);
            ioffset = check_offset_addition(ioffset, value2, ntree, pinfo, tvb);
            ioffset += align_4(tvb, ioffset);
            value1 = tvb_get_letohl(tvb, ioffset);  /* Privileges */
            proto_tree_add_item(ntree, hf_nds_privileges, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
            ioffset = ioffset + 4;
        }
        break;

    case MVTYPE_PROCESS_TAGS: /* Process tags and paths depending on name type returned. */
        switch (values->vflags) {

        case 8:  /* Tuned Name */
            proto_tree_add_item(ntree, hf_nds_tune_mark, tvb, ioffset, 2, ENC_BIG_ENDIAN);
            ioffset += 2;
            value1 = tvb_get_letohs(tvb, ioffset);
            valuestr = val_to_str_const(value1, nds_tuned_tags, "(Undefined Tuned Name Tag)");
            proto_tree_add_string_format(ntree, hf_value_string, tvb, ioffset,
                                         2, valuestr, "Tuned Name Tag -> %s", valuestr);
            ioffset += 2;
            ioffset += align_4(tvb, ioffset);
            if (value1 == 0) { /* RDN Hint - really just returns the dist name + timestamp info */
                value2 = tvb_get_letohl(tvb, ioffset);  /* Distinguished Name Len, String[len]*/
                ioffset = ioffset + 4;
                values->vstring = get_string(tvb, ioffset, value2);
                proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                      value2, values->vstring);
                ioffset += value2;
                ioffset += align_4(tvb, ioffset);
                ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                ns.nsecs = 0;
                proto_tree_add_time_format(ntree, hf_es_seconds, tvb, ioffset,
                                           4, &ns, "Creation Timestamp: %s",
                                           abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                ioffset += 4;
                proto_tree_add_item(ntree, hf_nds_replica_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
                proto_tree_add_item(ntree, hf_nds_event_num, tvb, ioffset,
                                    2, ENC_LITTLE_ENDIAN);
                ioffset = ioffset + 2;
            }
            else /* Process the full RDN history including ancestors */
            {
                value1 = tvb_get_letohl(tvb, ioffset);
                sub1item = proto_tree_add_uint_format(ntree, hf_nds_acl_del, tvb, ioffset,
                                                      4, value1, "Number of RDN Items %u", value1);
                sub1tree = proto_item_add_subtree(sub1item, ett_nds);
                ioffset = ioffset + 4;
                for (i=1; i <= value1; i++) {
                    sub2tree = proto_tree_add_subtree_format(sub1tree, tvb, ioffset, 0, ett_nds, NULL, "Item %u", i);
                    ioffset += align_4(tvb, ioffset);

                    value5 = tvb_get_letohl(tvb, ioffset);
                    valuestr = val_to_str_const(value5, nds_tuned_item_tags, "(Undefined Tuned Name Tag)");
                    if (value5 == 0) { /* Items are timestamp + Distinguished name (0 value == one entry)*/
                        proto_tree_add_string_format(sub2tree, hf_value_string, tvb, ioffset,
                                                     4, valuestr, "Item Tag -> %s", valuestr);
                        ioffset += 4;
                        ns.secs = tvb_get_letohl(tvb, ioffset);   /* Seconds */
                        ns.nsecs = 0;
                        proto_tree_add_time_format(sub2tree, hf_es_seconds, tvb, ioffset,
                                                   4, &ns, "Timestamp: %s",
                                                   abs_time_secs_to_str(pinfo->pool, ns.secs, ABSOLUTE_TIME_LOCAL, true));
                        ioffset += 4;
                        proto_tree_add_item(sub2tree, hf_nds_replica_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        proto_tree_add_item(sub2tree, hf_nds_event_num, tvb, ioffset,
                                            2, ENC_LITTLE_ENDIAN);
                        ioffset = ioffset + 2;
                        value2 = tvb_get_letohl(tvb, ioffset);  /* Distinguished Name Len, String[len]*/
                        ioffset = ioffset + 4;
                        values->vstring = get_string(tvb, ioffset, value2);
                        proto_tree_add_string(sub2tree, hf_mv_string, tvb, ioffset,
                                              value2, values->vstring);
                        ioffset += value2;
                    }
                    /* XXX: What if "multiple items" ?                 */
                    /*      What if "Undefined ... " ?                 */
                    /*      For now: we'll just keep on walking...     */
                    /*      Presumably we'll get a ReportedBoundsError */
                    /*       pretty quickly.                           */
                    else   /* Undefined or "multiple items" ... */
                    {
                        ioffset += 4;
                    }
                } /* for */
            } /* else */
            values->voffset=ioffset;
            break;
        default: /* All other name types are just a string */
            values->vstring = get_string(tvb, ioffset, values->vlength);
            proto_tree_add_string(ntree, hf_mv_string, tvb, ioffset,
                                  values->vlength, values->vstring);
            values->voffset=ioffset + values->vlength;
            /*ioffset = values->voffset;
            ioffset += align_4(tvb, ioffset);*/
            break;
        } /* switch (values->vflags) */
        break;

    case MVTYPE_PROCESS_ITERATOR: /* Process Iterator subverbs. */
        proto_tree_add_item(ntree, hf_nds_info_type, tvb, ioffset, 4, ENC_LITTLE_ENDIAN);
        ioffset += 4;
        value5 = tvb_get_letohl(tvb, ioffset);
        proto_tree_add_bitmask(ncp_tree, tvb, ioffset, hf_infoflagsl, ett_ncp, ncp_infoflagsl, ENC_LITTLE_ENDIAN);
        ioffset += 2;
        proto_tree_add_bitmask(ncp_tree, tvb, ioffset, hf_infoflagsh, ett_ncp, ncp_infoflagsh, ENC_LITTLE_ENDIAN);
        ioffset += 2;
        proto_tree_add_item(ntree, hf_nds_time_filter, tvb, ioffset, 4, ENC_BIG_ENDIAN);
        ioffset += 4;
        proto_tree_add_item(ntree, hf_nds_all_attr, tvb, ioffset, 4, ENC_BIG_ENDIAN);
        ioffset += 4;
        value2 = tvb_get_letohl(tvb, ioffset);
        sub1item = proto_tree_add_uint_format(ntree, hf_nds_number_of_items, tvb, ioffset,
                                              4, value2, "Number of Attributes %u", value2);
        sub1tree = proto_item_add_subtree(sub1item, ett_nds);
        ioffset += 4;
        for (i=1; i<=value2; i++) {
            sub2tree = proto_tree_add_subtree_format(sub1tree, tvb, ioffset, 0, ett_nds, NULL, "Attribute %u", i);
            ioffset += align_4(tvb, ioffset);
            value3 = tvb_get_letohl(tvb, ioffset);  /* Attribute Name */
            ioffset = ioffset + 4;
            values->vstring = get_string(tvb, ioffset, value3);
            proto_tree_add_string(sub2tree, hf_nds_attribute_dn, tvb, ioffset,
                                  value3, values->vstring);
            ioffset = ioffset + value3;

            if(tvb_captured_length_remaining(tvb, ioffset) < 4 )
            {
                break;
            }
        }
        ioffset += align_4(tvb, ioffset);
        value4 = tvb_get_letohl(tvb, ioffset);
        values->vstring = val_to_str_const(value4, iterator_subverbs, "(No Iteration Verb Found)");
        ioffset += 4;
        dissect_nds_iterator(ntree, tvb, pinfo, value4, value5, ioffset, true);

        values->vstring = wmem_strdup_printf(pinfo->pool, "(%s)", values->vstring);
        break;

    default:
        break;
    }
}

static void
dissect_ncp_89_6_request(tvbuff_t *tvb, proto_tree *volatile ncp_tree, uint32_t offset)
{
    uint32_t string_len, datatype, count, i;

    datatype = tvb_get_letohl(tvb, offset);
    proto_tree_add_item(ncp_tree, hf_ncp_data_type_flag, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    offset += 1;
    proto_tree_add_item(ncp_tree, hf_ncp_reserved5, tvb, offset, 5, ENC_NA);
    offset += 5;
    count = tvb_get_uint8(tvb, offset);
    proto_tree_add_item(ncp_tree, hf_ncp_path_count, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    offset += 1;
    for (i=0; i < count; i++) {
        if (datatype == 0) {
            string_len = (tvb_get_uint8(tvb, offset))+1;
            proto_tree_add_item(ncp_tree, hf_ncp_directory_path, tvb, offset+1, string_len-1, ENC_ASCII|ENC_NA);
        }
        else
        {
            string_len = (tvb_get_letohs(tvb, offset))+2;
            proto_tree_add_item(ncp_tree, hf_ncp_directory_path, tvb, offset+2, string_len-2, ENC_ASCII|ENC_NA);
        }
        offset += string_len;
        if(tvb_captured_length_remaining(tvb, offset) < 4 )
        {
            break;
        }
    }
}


static void
dissect_ncp_123_11_reply(tvbuff_t *tvb, proto_tree *volatile ncp_tree, ncp_req_hash_value *request_value)
{
    int string_len, loffset;

    loffset = 76;
    if (request_value->length == 7) {
        /* Undocumented, if request value length is 7 then the reply is offset by 8 bytes.
         * Unknown what these 8 bytes represent */
        loffset += 8;
    }
    string_len = tvb_get_uint8(tvb, loffset);
    proto_tree_add_item(ncp_tree, hf_ncp_file_name_12, tvb, loffset+1, string_len, ENC_ASCII|ENC_NA);
    loffset += string_len+1;
    string_len = tvb_get_uint8(tvb, loffset);
    proto_tree_add_item(ncp_tree, hf_ncp_name12, tvb, loffset+1, string_len, ENC_ASCII|ENC_NA);
    loffset += string_len+1;
    string_len = tvb_get_uint8(tvb, loffset);
    proto_tree_add_item(ncp_tree, hf_ncp_copyright, tvb, loffset+1, string_len, ENC_ASCII|ENC_NA);
}

static void
dissect_ncp_123_17_reply(tvbuff_t *tvb, packet_info* pinfo, proto_tree *volatile ncp_tree)
{
    proto_tree              *atree;
    proto_item              *aitem;
    uint32_t loffset, number_of_items, addr_type;
    uint16_t x;

    number_of_items = tvb_get_letohl(tvb, 36);
    proto_tree_add_item(ncp_tree, hf_ncp_items_in_packet, tvb, 36, 4, ENC_LITTLE_ENDIAN);
    loffset = 40;
    for (x = 1; x <= number_of_items; x++)
    {
        atree = proto_tree_add_subtree_format(ncp_tree, tvb, loffset, -1, ett_ncp, &aitem, "Network Address - %u", x);

        addr_type = tvb_get_uint8(tvb, loffset);
        proto_tree_add_item(atree, hf_ncp_transport_type, tvb, loffset, 1, ENC_LITTLE_ENDIAN);
        /* The address type is one byte of a 4 byte value. The next 4 bytes are
         * the length of the address. Since we already know the length based upon
         * the type of address, we can skip this value. So set the offset accourdingly */
        loffset += 8;

        switch (addr_type)
        {
        case 1:
            proto_tree_add_item(atree, hf_nds_net, tvb, loffset, 4, ENC_BIG_ENDIAN);
            proto_tree_add_item(atree, hf_nds_node, tvb, loffset+4, 6, ENC_NA);
            proto_tree_add_item(atree, hf_nds_socket, tvb, loffset+10, 2, ENC_BIG_ENDIAN);
            loffset += 12;
            break;
        case 5:
            proto_tree_add_item(atree, hf_nds_port, tvb, loffset, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item(atree, hf_add_ref_udp, tvb, loffset+2, 4, ENC_BIG_ENDIAN);
            loffset += 6;
            break;
        case 6:
            proto_tree_add_item(atree, hf_nds_port, tvb, loffset, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item(atree, hf_add_ref_tcp, tvb, loffset+2, 4, ENC_BIG_ENDIAN);
            loffset += 6;
            break;
        default:
            expert_add_info(pinfo, aitem, &ei_ncp_address_type);
            /* unknown type so read the length field and then
             * just skip the record and move on to the next */
            loffset += tvb_get_letohl(tvb, loffset - 4);
            break;
        }
        proto_item_set_end(aitem, tvb, loffset);
        if(tvb_captured_length_remaining(tvb, loffset) < 4 )
        {
            break;
        }
    }
}

static void
dissect_ncp_87_72_reply(tvbuff_t *tvb, proto_tree *volatile ncp_tree)
{
    proto_tree_add_item(ncp_tree, hf_ncp_bytes_actually_trans_64, tvb, tvb_captured_length_remaining(tvb, 0)-4, 4, ENC_BIG_ENDIAN);
}

static void
dissect_ncp_23_26_reply(tvbuff_t *tvb, proto_tree *volatile ncp_tree)
{
    /* For an IP-only server, the 4-byte IP address is placed into the 4-byte NetworkAddress
     * field of the NetworkAddressStruct, while the NetworkNodeAddress and NetworkSocket
     * fields are left blank. */
    if (tvb_get_letohl(tvb, 12)==0) {
        /* IP Address */
        proto_tree_add_item(ncp_tree, hf_ncp_ip_address, tvb, 8, 4, ENC_BIG_ENDIAN);
    }
    else
    {
        /* IPX Address */
        proto_tree_add_item(ncp_tree, hf_nds_net, tvb, 8, 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(ncp_tree, hf_nds_node, tvb, 12, 6, ENC_NA);
        proto_tree_add_item(ncp_tree, hf_nds_socket, tvb, 18, 2, ENC_BIG_ENDIAN);
    }
    proto_tree_add_item(ncp_tree, hf_ncp_connection_type, tvb, 20, 1, ENC_NA);
}

/*
 * XXX - this actually handles both 89 3 and 89 20.
 * It should also probably handle 87 3 and 87 20.
 */
static void
dissect_ncp_8x20req(tvbuff_t *tvb, proto_tree *volatile ncp_tree, uint32_t offset, unsigned func)
{
    uint32_t string_len, str_length, buffer_offset;
    int i;
    uint8_t c_char;
    wmem_strbuf_t *string_buf;
    int length_remaining = 0;

    length_remaining = tvb_captured_length_remaining(tvb, offset);
    /*
     * XXX - the Novell documentation for function code 89 (0x59) says
     * that the length is 1 byte if the data format byte is 0 for ASCII
     * and 2 bytes if the data format byte is 1 for UTF-8.
     *
     * The documentation for function code 87 (0x57) says it's always
     * 1 byte - and that there's no data format byte.
     */
    if (func == 0x57)
    {
        string_len = tvb_get_uint8(tvb, offset);
        str_length = tvb_get_uint8(tvb, offset);
    }
    else
    {
        string_len = tvb_get_letohs(tvb, offset);
        str_length = tvb_get_letohs(tvb, offset);
    }

    if((int)str_length > length_remaining)
    {
        THROW(ReportedBoundsError);
    }

    string_buf = wmem_strbuf_new(wmem_packet_scope(), NULL);
    offset++;
    buffer_offset = offset;

    /*
     * XXX - should this treat ASCII and UTF-8 differently?
     */
    for ( i = 0; i <= (int)str_length; i++ )
    {
        c_char = tvb_get_uint8(tvb, buffer_offset );
        if (c_char<0x20 || c_char>0x7e)
        {
            /* Not printable ASCII */
            if (c_char == 0xff)
            {
                /*
                 * 0xff is not a valid ASCII character and is not
                 * part of a valid UTF-8 octet sequence.
                 *
                 * What is the significance of 0xbf, 0xaa, and 0xae
                 * here?
                 *
                 * Will these show up in UTF-8 strings?
                 */
                buffer_offset++;
                length_remaining--;
                c_char = tvb_get_uint8(tvb, buffer_offset);
                if (c_char == '?')
                {
                    wmem_strbuf_append_c(string_buf, '?');
                    proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "Wildcard Question");
                }
                else if (c_char == '*')
                {
                    wmem_strbuf_append_c(string_buf, '*');
                    proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "Wildcard Asterisk");
                }
                else if (c_char == 0xbf)
                {
                    /*
                     * For what it's worth, in ISO 8859-1, 0xbf is a
                     * Spanish-style upside-down question mark.
                     */
                    wmem_strbuf_append_c(string_buf, '?');
                    proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "DOS Wildcard Question");
                }
                else if (c_char == 0xaa)
                {
                    /*
                     * But, in 8859-1, this is a feminine ordinal indicator
                     * (underlined subscripted "a").
                     */
                    c_char = '*';
                    wmem_strbuf_append_c(string_buf, c_char);
                    proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "DOS Wildcard Asterisk");
                }
                else if (c_char == 0xae)
                {
                    /*
                     * And this is a registered trademark symbol.
                     */
                    wmem_strbuf_append_c(string_buf, '.');
                    proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "DOS Wildcard Period");
                }
                else
                {
                    wmem_strbuf_append_c(string_buf, '.');
                }
            }
            else if (c_char == 0xef)
            {
                /*
                 * XXX - if these 3-character sequences are considered
                 * as UTF-8 sequences, they map to characters in the
                 * private use range from f87b to f87f.
                 *
                 * Is that what's happening here?
                 *
                 * If so, will these show up in ASCII strings?
                 */
                buffer_offset++;
                length_remaining--;
                c_char = tvb_get_uint8(tvb, buffer_offset);
                if (c_char == 0xa3)
                {
                    buffer_offset++;
                    length_remaining--;
                    c_char = tvb_get_uint8(tvb, buffer_offset);
                    if (c_char == 0xbb)
                    {
                        wmem_strbuf_append_c(string_buf, '?');
                        proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "Wildcard Question");
                    }
                    else if (c_char == 0xbc)
                    {
                        wmem_strbuf_append_c(string_buf, '*');
                        proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "Wildcard Asterisk");
                    }
                    else if (c_char == 0xbd)
                    {
                        c_char = '?';
                        wmem_strbuf_append_c(string_buf, c_char);
                        proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "DOS Wildcard Question");
                    }
                    else if (c_char == 0xbe)
                    {
                        wmem_strbuf_append_c(string_buf, '*');
                        proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "DOS Wildcard Asterisk");
                    }
                    else if (c_char == 0xbf)
                    {
                        wmem_strbuf_append_c(string_buf, '.');
                        proto_tree_add_uint_format_value(ncp_tree, hf_search_modifier, tvb, buffer_offset-1, 2, c_char, "DOS Wildcard Period");
                    }
                }
            }
            else
            {
                if (c_char != 0x00)
                {
                    wmem_strbuf_append_c(string_buf, '.');
                }
                else
                {
                    i--;
                    str_length--;
                    offset++;
                }
            }
        }
        else
        {
            /* printable ASCII */
            wmem_strbuf_append_c(string_buf, c_char);
        }
        buffer_offset++;
        length_remaining--;

        if(length_remaining==1)
        {
            break;
        }
        if (i >= 1023) { /* Don't process beyond the size of our variable */
            break;       /* If string is too long just return the first 1K. */
        }
    }

    proto_tree_add_string(ncp_tree, hf_search_pattern, tvb, offset, string_len, wmem_strbuf_get_str(string_buf));
}

static void
dissect_ncp_8x20reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *volatile ncp_tree,
                      const ncp_record *ncp_rec, ncp_req_hash_value *request_value)
{
    uint16_t            x;
    uint32_t            loffset, number_of_items, str_length;
    ptvcursor_t         *ptvc = NULL;
    proto_tree          *atree, *btree;
    proto_item          *aitem, *bitem;

    if ((request_value->req_mask ==0) & (request_value->req_mask_ext == 0))
    {
        return;
    }
    atree = proto_tree_add_subtree(ncp_tree, tvb, 8, 9, ett_ncp, &aitem, "Search Sequence");

    proto_tree_add_item(atree, hf_ncp_volume_number, tvb, 8, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(atree, hf_ncp_directory_entry_number, tvb, 9, 4, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(atree, hf_ncp_sequence_number, tvb, 13, 4, ENC_LITTLE_ENDIAN);

    proto_tree_add_item(ncp_tree, hf_ncp_more_flag, tvb, 17, 1, ENC_LITTLE_ENDIAN);
    number_of_items = tvb_get_letohs(tvb, 18);
    proto_tree_add_item(ncp_tree, hf_ncp_info_count, tvb, 18, 2, ENC_LITTLE_ENDIAN);
    loffset = 20;
    for (x = 1; x <= number_of_items; x++ )
    {
        atree = proto_tree_add_subtree_format(ncp_tree, tvb, loffset, -1, ett_ncp, &aitem, "Information Item %u", x);

        /* Data Stream Space Allocated */
        if (request_value->req_mask & 0x0002) {
            proto_tree_add_item(atree, hf_ncp_data_stream_space_alloc, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            loffset += 4;
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 4;
            }
        }
        /* Attributes */
        if (request_value->req_mask & 0x0004) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Attributes");

            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_attributes_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 6;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 6;
            }
        }
        /* Data Stream Size */
        if (request_value->req_mask & 0x0008) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Data Stream Size");

            proto_tree_add_item(btree, hf_ncp_data_stream_size, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            loffset += 4;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 4;
            }
        }
        /* Total Stream Size */
        if (request_value->req_mask & 0x0010) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Total Stream Size");

            proto_tree_add_item(btree, hf_ncp_ttl_ds_disk_space_alloc, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            proto_tree_add_item(btree, hf_ncp_number_of_data_streams, tvb, loffset+4, 2, ENC_LITTLE_ENDIAN);
            loffset += 6;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 6;
            }
        }
        /* Extended Attributes oldstyle location*/
        if (request_value->req_mask & 0x0020 && !ncp_newstyle) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Extended Attributes");
            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_ea_info_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 12;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false && !ncp_newstyle) {
                loffset += 12;
            }
        }
        /* Extended Attributes new style location*/
        if (request_value->req_mask & 0x0020 && ncp_newstyle) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Extended Attributes");

            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_ea_info_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 12;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false && ncp_newstyle) {
                loffset += 12;
            }
        }
        /* Archive Information */
        if (request_value->req_mask & 0x0040) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Archive");
            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_archive_info_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 8;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 8;
            }
        }
        /* Modification Information */
        if (request_value->req_mask & 0x0080) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Modification");

            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_modify_info_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 10;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 10;
            }
        }
        /* Creation Information old style location */
        if (request_value->req_mask & 0x0100 && !ncp_newstyle) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Creation");
            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_creation_info_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 8;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false && !ncp_newstyle) {
                loffset += 8;
            }
        }
        /* Creation Information new style location */
        if (request_value->req_mask & 0x0100 && ncp_newstyle) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Creation");
            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_creation_info_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 8;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false && ncp_newstyle) {
                loffset += 8;
            }
        }
        /* Name Space Information */
        if (request_value->req_mask & 0x0200) {
            proto_tree_add_item(atree, hf_ncp_creator_name_space_number, tvb, loffset, 1, ENC_LITTLE_ENDIAN);
            loffset += 4;
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 4;
            }
        }
        /* Directory Entry */
        if (request_value->req_mask & 0x0400) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Directory Entry");
            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_dir_entry_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 12;
            proto_item_set_end(bitem, tvb, loffset);
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 12;
            }
        }
        /* Rights Information */
        if (request_value->req_mask & 0x0800) {
            ptvc = ptvcursor_new(pinfo->pool, atree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_rights_info_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 2;
        }
        else
        {
            if ((request_value->req_mask_ext & 0x8000)==false) {
                loffset += 2;
            }
        }
        /* Return ID Information */
        if (request_value->req_mask & 0x1000) {
            proto_tree_add_item(atree, hf_ncp_curr_ref_id, tvb, loffset, 2, ENC_LITTLE_ENDIAN);
            loffset += 2;
        }
        /* Return Name Space Attributes Information */
        if (request_value->req_mask & 0x2000) {
            proto_tree_add_item(atree, hf_ncp_attr_def_32, tvb, loffset, 1, ENC_LITTLE_ENDIAN);
            loffset += 4;
        }
        /* Return Actual Information */
        if (request_value->req_mask & 0x4000) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Actual");

            proto_tree_add_item(btree, hf_ncp_data_stream_num_long, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            proto_tree_add_item(btree, hf_ncp_data_stream_fat_blks, tvb, loffset+4, 4, ENC_LITTLE_ENDIAN);
            loffset += 8;
            proto_item_set_end(bitem, tvb, loffset);
        }
        /* Return Logical Information */
        if (request_value->req_mask & 0x8000) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Logical");
            proto_tree_add_item(btree, hf_ncp_number_of_data_streams_long, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            number_of_items = tvb_get_letohs(tvb, loffset);
            loffset += 4;
            for (x = 1; x <= number_of_items; x++ )
            {
                proto_tree_add_item(btree, hf_ncp_data_stream_num_long, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(btree, hf_ncp_data_stream_size, tvb, loffset+4, 4, ENC_LITTLE_ENDIAN);
                loffset += 8;
            }
            proto_item_set_end(bitem, tvb, loffset);
        }
        /* Last Update */
        if (request_value->req_mask_ext & 0x0001 && ncp_newstyle) {
            proto_tree_add_item(atree, hf_ncp_sec_rel_to_y2k, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            loffset += 4;
        }
        /* Dos Name */
        if (request_value->req_mask_ext & 0x0002 && ncp_newstyle) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "DOS Name");

            if (ncp_rec->func == 0x57) {
                str_length = tvb_get_uint8(tvb, loffset);
                loffset += 1;
            }
            else
            {
                str_length = tvb_get_letohs(tvb, loffset);
                loffset += 2;
            }
            proto_tree_add_item(btree, hf_ncp_file_name_12, tvb, loffset, str_length, ENC_ASCII|ENC_NA);
            loffset += str_length;
            proto_item_set_end(bitem, tvb, loffset);
        }
        /* Flush Time */
        if (request_value->req_mask_ext & 0x0004 && ncp_newstyle) {
            ptvc = ptvcursor_new(pinfo->pool, atree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_flush_time_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 4;
        }
        /* Parental */
        if (request_value->req_mask_ext & 0x0008 && ncp_newstyle) {
            proto_tree_add_item(atree, hf_ncp_parent_base_id, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            loffset += 4;
        }
        /* MAC finder */
        if (request_value->req_mask_ext & 0x0010 && ncp_newstyle) {
            proto_tree_add_item(atree, hf_ncp_mac_finder_info, tvb, loffset, 32, ENC_NA);
            loffset += 32;
        }
        /* Sibling */
        if (request_value->req_mask_ext & 0x0020 && ncp_newstyle) {
            proto_tree_add_item(atree, hf_ncp_sibling_count, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
            loffset += 4;
        }
        /* Effective */
        if (request_value->req_mask_ext & 0x0040 && ncp_newstyle) {
            proto_tree_add_item(atree, hf_ncp_effective_rights, tvb, loffset, 1, ENC_LITTLE_ENDIAN);
            loffset += 4;
        }
        /* MAC Date */
        if (request_value->req_mask_ext & 0x0080 && ncp_newstyle) {
            btree = proto_tree_add_subtree(atree, tvb, loffset, -1, ett_ncp, &bitem, "Mac Date");

            ptvc = ptvcursor_new(pinfo->pool, btree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_mac_time_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 8;
            proto_item_set_end(bitem, tvb, loffset);
        }
        /* Last Access */
        if (request_value->req_mask_ext & 0x0100 && ncp_newstyle) {
            ptvc = ptvcursor_new(pinfo->pool, atree, tvb, loffset);
            process_ptvc_record(ptvc, pinfo, ptvc_struct_last_access_time_struct,
                    NULL, true, ncp_rec, false);
            ptvcursor_free(ptvc);
            loffset += 2;
        }
        /* 64 bit file sizes */
        if (request_value->req_mask_ext & 0x0400 && ncp_newstyle) {
            proto_tree_add_item(atree, hf_ncp_f_size_64bit, tvb, loffset, 8, ENC_LITTLE_ENDIAN);
            loffset += 8;
        }
        /* We always return the file name */
        if (ncp_rec->func == 0x57) {
            str_length = tvb_get_uint8(tvb, loffset);
            loffset += 1;
        }
        else
        {
            str_length = tvb_get_letohs(tvb, loffset);
            loffset += 2;
        }
        proto_tree_add_item(atree, hf_ncp_file_name_12, tvb, loffset, str_length, ENC_UTF_8);
        loffset += str_length;

        proto_item_set_end(aitem, tvb, loffset);

        if(tvb_captured_length_remaining(tvb, loffset) < 4 )
        {
                break;
        }
    }
}

static void
dissect_ncp_123_62_reply(tvbuff_t *tvb, proto_tree *volatile ncp_tree)
{
    uint8_t cmd_type;
    const char * param_string;
    int ret_len;

    cmd_type = tvb_get_uint8(tvb, 8+16);
    param_string = (const char *)tvb_get_stringz_enc(wmem_packet_scope(), tvb, 8+24, &ret_len, ENC_ASCII);

    switch (cmd_type) {
    case 0:   /* { 0x00, "Numeric Value" }, */
    case 2:   /* { 0x02, "Ticks Value" },   */
    case 4:   /* { 0x04, "Time Value" },    */
    case 6:   /* { 0x06, "Trigger Value" }, */
    case 7:   /* { 0x07, "Numeric Value" }, */
        proto_tree_add_item(ncp_tree, hf_srvr_param_number, tvb, 37+(int)strlen(param_string), 4, ENC_LITTLE_ENDIAN);
        break;
    case 1:   /* { 0x01, "Boolean Value" }, */
        proto_tree_add_item(ncp_tree, hf_srvr_param_boolean, tvb, 37+(int)strlen(param_string), 1, ENC_LITTLE_ENDIAN);
        break;
    case 5:   /* { 0x05, "String Value" },  */
        proto_tree_add_item(ncp_tree, hf_srvr_param_string, tvb, 37+(int)strlen(param_string), -1, ENC_ASCII|ENC_NA);
        break;
    default:
        break;
    }
}

/*
 * Defrag logic
 *
 * NDS fragment not being set to 0xffffffff indicates we are inside or at the
 * beginning of a fragment. But when the end of the fragment
 * is encounterd the flag is set to 0xffffffff. So we must mark what the
 * frame number is of the end fragment so that we will be
 * able to redissect if the user clicks on the packet
 * or resorts/filters the trace.
 *
 * Once we are certain that we are in a fragment sequence
 * then we can just process each fragment in this conversation
 * until we reach the fragment == 0xffffffff packet.
 *
 * We will be able to easily determine if a conversation is a fragment
 * with the exception of the last packet in the fragment. So remember
 * the last fragment packet number.
 *
 * Also the NDS dissection requires the values of NDS Verb, Version, and Flags.
 * Without these values being remembered from the first request packet then
 * we will be unable to dissect the reply packet. For this reason we remember
 * these values on the first fragment and then populate the values in the final
 * fragment. We only do this on the first dissection.
 */
void
nds_defrag(tvbuff_t *tvb, packet_info *pinfo, uint32_t nw_connection, uint8_t sequence, uint16_t type, proto_tree *tree, struct novell_tap *ncp_tap)
{
    int                 i, frag_count=0;
    uint32_t            tid = 1;
    tvbuff_t            *frag_tvb = NULL;
    fragment_head       *fd_head;
    ncp_req_hash_value  *request_value = NULL;
    conversation_t      *conversation;
    uint32_t            nds_frag;

    for (i = 0; i < 99; i++) {
        if (!frags[i].nds_fragmented)
        {
            frags[i].nds_frag = 0xfffffff0;
        }
    }
    /* Check to see if defragmentation is enabeled in the dissector */
    if (!nds_defragment) {
        dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
        return;
    }
    /* Has this already been dissected? */
    if (!pinfo->fd->visited) {
        /* Find the conversation whence the request would have come. */
        conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                         CONVERSATION_NCP, nw_connection, nw_connection, 0);
        if (conversation != NULL) {
            /* find the record telling us the request made that caused
               this reply */
            request_value = ncp_hash_lookup(conversation, sequence, pinfo->num);
            if (!request_value) {
                dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
                return;
            }
            p_add_proto_data(wmem_file_scope(), pinfo, proto_ncp, 0, (void*) request_value);
        }
        /* else... we haven't seen an NCP Request for that conversation and sequence. */
        else
            {
                dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
                return;
            }
    }
    else {
        request_value = (ncp_req_hash_value *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ncp, 0);
        if (!request_value) {
                dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
                return;
        }
    }
    /* Validate that this is an NDS packet */
    /* If this isn't an NDS packet then just return */
    if (!request_value->ncp_rec ||
        request_value->ncp_rec->func!=104 || request_value->ncp_rec->subfunc!=2) {
        dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
        return;
    }
    /* Check to see if there is at least enough packet info to get the fragment flag */
    if (tvb_reported_length_remaining(tvb, 12) < 4) {
        dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
        return;
    }
    /* Get the fragment flag */
    nds_frag = tvb_get_letohl(tvb, 12);

    /* Now we need to find if this is a new fragment or already one defined. */
    /* We currently limit the maximum number of simultaneous fragments to 100. */
    for (i=0; i<100; i++)
    {
        if (frags[i].nds_frag == nds_frag || frags[i].nds_frag == 0xfffffff0)
        {
            if (frags[i].nds_frag == 0xfffffff0)
                {
                    frags[i].nds_length = 0;
                    frags[i].nds_frag = nds_frag;
                    frags[i].nds_fragmented = true;
                    frags[i].sequence = 0;
                }
            break;
        }
    }
    if (i > 99)
        return;

    frag_count = i;

    /* is this the end of an existing fragment or just another reply */
    if (nds_frag == 0xffffffff && request_value->nds_frag_num == 0xffffffff)
    {
        dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
        return;
    }

    /* Now we process the fragments */
    if (request_value->nds_frag || (request_value->nds_end_frag == pinfo->num))
    {
        unsigned len;

        /* Check to see of this is a fragment. If so then mark as a fragment. */
        if (frags[frag_count].nds_frag==0xffffffff) {
            request_value->nds_frag = false;
            /* nds_length of 0 means start of fragment */
            frags[frag_count].nds_length = 0;
        }
        else
        {
            if (frags[frag_count].nds_length == 0)
            {
                frags[frag_count].nds_length = tvb_get_letohl(tvb, 0);
            }
        }
        /*
         * Fragment
         *
         */
        tid = (pinfo->srcport+pinfo->destport);
        len = tvb_reported_length(tvb);
        if (len > 0 && tvb_bytes_exist(tvb, 0, len))
        {
            if (frags[frag_count].nds_length > len)
            {
                /* This is the first fragment so remember the verb, version, and flags. */
                frags[frag_count].nds_frag_verb = request_value->nds_request_verb;
                frags[frag_count].nds_frag_version = request_value->nds_version;
                frags[frag_count].nds_frag_flags = request_value->req_nds_flags;
                frags[frag_count].nds_frag_prot_flags = request_value->req_nds_prot_flags;
                fd_head = fragment_add_seq_next(&nds_reassembly_table, tvb, 0, pinfo, tid, NULL, len, request_value->nds_frag);
                frags[frag_count].sequence = sequence;
                frags[frag_count].nds_length = 1;
            }
            else
            {
                /* Subsequent fragments should be offset by 16 since we do not need */
                /* the additional fragment handle and size fields in our composite data */
                /* Also do not add retransmitted packets, just mark and return */
                if (!pinfo->fd->visited)
                {
                    if (sequence != frags[frag_count].sequence) {
                        fd_head = fragment_add_seq_next(&nds_reassembly_table, tvb, 16, pinfo, tid, NULL, len-16, request_value->nds_frag);
                        frags[frag_count].sequence = sequence;
                    }
                    else
                    {
                        col_add_fstr(pinfo->cinfo, COL_INFO, "[Retransmitted NDS Fragment 0x%08x]", frags[frag_count].nds_frag);
                        return;
                    }
                }
                else
                {
                    fd_head = fragment_add_seq_next(&nds_reassembly_table, tvb, 16, pinfo, tid, NULL, len-16, request_value->nds_frag);
                    frags[frag_count].sequence = sequence;
                }
            }
            if (fd_head != NULL)
            {
                /* Is this the last fragment? nds_frag will indicate */
                if (fd_head->next != NULL && !request_value->nds_frag)
                {
                    frag_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
                    add_new_data_source(pinfo,
                                        frag_tvb,
                                        "Reassembled NDS");
                    /* Show all fragments. */
                    if (tree)
                    {
                        proto_item *frag_tree_item;
                        show_fragment_seq_tree(fd_head,
                                               &nds_frag_items,
                                               tree, pinfo,
                                               frag_tvb, &frag_tree_item);
                        tid++;
                    }

                    if (!pinfo->fd->visited)
                    {
                        /* Now we need to find the original fragment number. */
                        /* Get the fragment flag */
                        nds_frag = tvb_get_letohl(frag_tvb, 12);
                        for (i=0; i<100; i++)
                        {
                            if (frags[i].nds_frag == nds_frag)
                            {
                                break;
                            }
                        }
                        if (i > 99)
                            return;
                        if (frags[i].nds_frag == 0xffffffff)
                        {
                            /* Error can't find fragment */
                            /*DISSECTOR_ASSERT(0);*/
                        }
                        frag_count = i;
                        /* Remember this fragment information so we can dissect.
                         * Only do this on the first dissection. After the first
                         * dissection we will just read the memory values.
                         */
                        request_value->nds_end_frag = pinfo->num;
                        request_value->nds_request_verb = frags[frag_count].nds_frag_verb;
                        request_value->nds_version = frags[frag_count].nds_frag_version;
                        request_value->req_nds_flags = frags[frag_count].nds_frag_flags;
                        request_value->req_nds_prot_flags = frags[frag_count].nds_frag_prot_flags;
                    }

                }
                else
                {
                    /* This is either a beginning or middle fragment on second dissection */
                    frag_tvb = tvb_new_subset_remaining(tvb, 0);
                    if (request_value->nds_frag)
                    {
                      col_add_fstr(pinfo->cinfo, COL_INFO, "[NDS Fragment 0x%08x]", frags[frag_count].nds_frag);
                    }
                }
            }
            else
            {
                /* Fragment from first pass of dissection */
                if (request_value->nds_frag)
                {
                   col_add_fstr(pinfo->cinfo, COL_INFO, "[NDS Fragment 0x%08x]", frags[frag_count].nds_frag);
                }

                frag_tvb = NULL;
            }
        }
        else
        {
            /*
             * There are no bytes so Dissect this
             */
            frag_tvb = tvb_new_subset_remaining(tvb, 0);
        }
        if (frag_tvb == NULL)
        {
            /* This is a fragment packet */
            frag_tvb = tvb_new_subset_remaining(tvb, 0);
            nds_data_handle = find_dissector("data");
            call_dissector(nds_data_handle, frag_tvb, pinfo, tree);
        }
        else
        {
            /* This is the end fragment so dissect */
            if (!request_value->nds_frag) {
                frags[frag_count].nds_length = 0;
                dissect_ncp_reply(frag_tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
            }
        }
    }
    else
    {
        /* This is not any fragment packet */
        request_value->nds_frag = false;
        /* Trap for retransmitted end fragment */
        if (request_value->nds_end_frag < pinfo->num) {
            col_add_fstr(pinfo->cinfo, COL_INFO, "[Retransmitted end of NDS Fragment 0x%08x, see packet #%d for details.]", request_value->nds_frag_num, request_value->nds_end_frag);
        }
        else
        {
            dissect_ncp_reply(tvb, pinfo, nw_connection, sequence, type, tree, ncp_tap);
        }
    }
}

static bool ncp2222_dfilters_compiled;

static void
ncp2222_compile_dfilters(void)
{
    int i;
    df_error_t *df_err;

    for (i = 0; i < NUM_REQ_CONDS; i++) {
        if (!dfilter_compile((const char*)req_conds[i].dfilter_text,
                             &req_conds[i].dfilter, &df_err)) {
            g_error("NCP dissector failed to compile dfilter \"%s\": %s\n",
                      req_conds[i].dfilter_text, df_err->msg);
            df_error_free(&df_err);
            ws_assert_not_reached();
        }
    }
}

void
dissect_ncp_request(tvbuff_t *tvb, packet_info *pinfo,
                uint32_t nw_connection, uint8_t sequence,
                uint16_t type, bool is_lip_echo_allocate_slot,
                proto_tree *volatile ncp_tree)
{
    volatile uint8_t        func=0;
    volatile uint8_t        subfunc = 0;
    bool                    requires_subfunc = false;
    bool                    has_length = false;
    ncp_req_hash_value      *volatile request_value = NULL;
    const ncp_record        *volatile ncp_rec = NULL;
    conversation_t          *conversation;
    ptvcursor_t             *volatile ptvc = NULL;
    proto_tree              *temp_tree = NULL;
    volatile bool           run_req_cond = false;
    volatile unsigned long  exception_code;
    const char              *volatile message;
    proto_item              *ti;


    /* We're dissecting an ncp2222 request; Compile the dfilters (if not yet done). */
    /* XXX: We do this here rather than at "post-registration" (as previouly done)  */
    /*      so compiling over 100 dfilters is done only if needed (thus avoiding    */
    /*      compiling the dfilters each time Wireshark is started.                  */
    if (! ncp2222_dfilters_compiled) {
        ncp2222_compile_dfilters();
        ncp2222_dfilters_compiled = true;
    }

    /* Determine which ncp_record to use. */
    switch (type) {
    case NCP_ALLOCATE_SLOT:
        if (is_lip_echo_allocate_slot) {
            ncp_rec = &ncplip_echo;
        } else {
            ncp_rec = &ncp1111_request;
            if (ncp_echo_conn) {
                expert_add_info(pinfo, NULL, &ei_ncp_connection_request);
            }
        }
        break;
    case NCP_SERVICE_REQUEST:
        func = tvb_get_uint8(tvb, 6);
        requires_subfunc = ncp_requires_subfunc(func);
        has_length = ncp_has_length_parameter(func);
        if (requires_subfunc) {
            if (has_length) {
                subfunc = tvb_get_uint8(tvb, 9);
            }
            else {
                subfunc = tvb_get_uint8(tvb, 7);
            }
        }
        ncp_rec = ncp_record_find(func, subfunc);
        break;
    case NCP_DEALLOCATE_SLOT:
        ncp_rec = &ncp5555_request;
        if (ncp_echo_conn) {
            expert_add_info_format(pinfo, NULL, &ei_ncp_destroy_connection, "Destroy Connection %u Request", nw_connection);
        }
        break;
    case NCP_BROADCAST_SLOT:
        ncp_rec = &ncpbbbb_request;
        break;
    case NCP_LIP_ECHO:
        ncp_rec = &ncplip_echo;
        break;
    default:
        ncp_rec = NULL;
        break;
    }

    /* Fill in the INFO column. */
    if (ncp_rec) {
        col_add_fstr(pinfo->cinfo, COL_INFO, "C %s", ncp_rec->name);
    }
    else {
        if (requires_subfunc) {
            col_add_fstr(pinfo->cinfo, COL_INFO,
                            "C Unknown Function %u %u (0x%02X/0x%02x)",
                            func, subfunc, func, subfunc);
            return;
        }
        else {
            col_add_fstr(pinfo->cinfo, COL_INFO,
                            "C Unknown Function %u (0x%02x)",
                            func, func);
            return;
        }
    }

    if (!pinfo->fd->visited) {
        /* This is the first time we've looked at this packet.
           Keep track of the address and connection whence the request
           came, and the address and connection to which the request
           is being sent, so that we can match up calls with replies.
           (We don't include the sequence number, as we may want
           to have all packets over the same connection treated
           as being part of a single conversation so that we can
           let the user select that conversation to be displayed.) */
        conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                         CONVERSATION_NCP, nw_connection, nw_connection, 0);

        if (conversation == NULL) {
            /* It's not part of any conversation - create a new one. */
            conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
                                            CONVERSATION_NCP, nw_connection, nw_connection, 0);
        }
        request_value = ncp_hash_insert(conversation, sequence, ncp_rec, pinfo->num);
        request_value->req_frame_num = pinfo->num;
        request_value->req_frame_time = pinfo->abs_ts;

        /* If this is the first time we're examining the packet,
         * check to see if this NCP type uses a "request condition".
         * If so, we have to build a proto_tree because request conditions
         * use display filters to work, and without a proto_tree,
         * display filters can't possibly work. */
        if (ncp_rec) {
            if (ncp_rec->req_cond_indexes) {
                run_req_cond = true;
            }
        }
    }

    /* If we have to handle a request condition, or have to
       add to the Info column, we need to construct a protocol
       tree.  If we already have a proto_tree, then wonderful.
       If we don't, we need to build one. */
    if (run_req_cond && !ncp_tree) {
        temp_tree = proto_tree_create_root(pinfo);
        proto_tree_set_visible(temp_tree, false);
        ti = proto_tree_add_item(temp_tree, proto_ncp, tvb, 0, -1, ENC_NA);
        ncp_tree = proto_item_add_subtree(ti, ett_ncp);
    }

    if (ncp_tree) {
        /* If the dissection throws an exception, be sure to free
         * the temporary proto_tree that was created. Because of the
         * way the CLEANUP_PUSH macro works, we can't put it in an 'if'
         * block; it has to be in the same scope as the terminating
         * CLEANUP_POP or CLEANUP_POP_AND_ALLOC. So, we always
         * call CLEANUP_POP and friends, but the value of temp_tree is
         * NULL if no cleanup is needed, and non-null if cleanup is needed. */
        CLEANUP_PUSH_PFX(xx,free_proto_tree, temp_tree);

#ifdef FAKE_TREE_IS_VISIBLE
        PTREE_DATA(ncp_tree)->visible=1;
#endif

        /* Before the dissection, if we're saving data for a request
         * condition, we have to prime the proto tree using the
         * dfilter information */
        if (run_req_cond) {
            const int *needed;
            dfilter_t *dfilter;

            needed = ncp_rec->req_cond_indexes;

            while (*needed != -1) {
                dfilter = req_conds[*needed].dfilter;
                /* Prime the proto_tree with "interesting fields". */
                dfilter_prime_proto_tree(dfilter, ncp_tree);
                needed++;
            }
        }

        switch (type) {
        case NCP_BROADCAST_SLOT:
            ; /* nothing */
            break;

        case NCP_SERVICE_REQUEST:
            proto_tree_add_uint_format_value(ncp_tree, hf_ncp_func, tvb, 6, 1,
                                       func, "%u (0x%02X), %s",
                                       func, func, ncp_rec ? ncp_rec->name : "Unknown");
            break;

        default:
            ; /* nothing */
            break;
        }
        if (request_value) {
            request_value->length = 0;
        }
        if (requires_subfunc) {
            if (has_length) {
                if (request_value && func==123) {
                    request_value->length = tvb_get_ntohs(tvb, 7);
                }
                proto_tree_add_item(ncp_tree, hf_ncp_length, tvb, 7,
                                    2, ENC_BIG_ENDIAN);
                proto_tree_add_uint(ncp_tree, hf_ncp_subfunc, tvb, 9, 1, subfunc);
                ptvc = ptvcursor_new(pinfo->pool, ncp_tree, tvb, 10);
            }
            else {
                proto_tree_add_uint(ncp_tree, hf_ncp_subfunc, tvb, 7, 1, subfunc);
                ptvc = ptvcursor_new(pinfo->pool, ncp_tree, tvb, 8);
            }
        }
        else {
            ptvc = ptvcursor_new(pinfo->pool, ncp_tree, tvb, 7);
        }

        /* The group is not part of the packet, but it's useful
         * information to display anyway. Put it in the tree for filtering and tap use*/
        if (ncp_rec) {
            ti = proto_tree_add_uint_format_value(ncp_tree, hf_ncp_group, tvb, 0, 0, ncp_rec->group, "%s", ncp_groups[ncp_rec->group]);
            proto_item_set_generated(ti);
        }

        exception_code = 0;
        message = NULL;
        if (ncp_rec && ncp_rec->request_ptvc) {
            clear_repeat_vars();
            /*
             * We need to remember the results even if we
             * throw an exception dissecting this request,
             * so that we can properly dissect the reply.
             * We catch any exceptions thrown when
             * dissecting the request, and re-throw them
             * after saving the results of any conditional
             * tests.
             */
            TRY {
                process_ptvc_record(ptvc, pinfo, ncp_rec->request_ptvc, NULL, true, ncp_rec, true);
            } CATCH_ALL {
                exception_code = EXCEPT_CODE;
                message = GET_MESSAGE;
            }
            ENDTRY;
        }
        ptvcursor_free(ptvc);

        /* Now that the dissection is done, do we need to run
         * some display filters on the resulting tree in order
         * to save results for "request conditions" ? */
        if (run_req_cond) {
            const int   *needed;
            bool        *results;
            dfilter_t   *dfilter;

            results = (bool *)wmem_alloc0(wmem_file_scope(), sizeof(bool)*NUM_REQ_CONDS);
            needed = ncp_rec->req_cond_indexes;

            while (*needed != -1) {
                /* ncp_tree is not a root proto_tree, but
                 * dfilters will still work on it. */
                dfilter = req_conds[*needed].dfilter;
                results[*needed] = dfilter_apply(dfilter, ncp_tree);
                needed++;
            }

            /* Save the results so the reply packet dissection
             * get to them. */
            request_value->req_cond_results = results;
        }

        if (!request_value)
        {
             conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                                 CONVERSATION_NCP, nw_connection, nw_connection, 0);
             if (conversation != NULL) {
                 /* find the record telling us the request made that caused
                    this reply */
                 request_value = ncp_hash_lookup(conversation, sequence, pinfo->num);
              }
        }
        /* SecretStore packets are dessected in packet-ncp-sss.c */
        if (func == 0x5c && ncp_tree) {
            dissect_sss_request(tvb, pinfo, ncp_tree, request_value);
        }
        /* NMAS packets are dessected in packet-ncp-nmas.c */
        if (func == 0x5e && ncp_tree) {
            dissect_nmas_request(tvb, pinfo, ncp_tree, request_value);
        }

        /* Store NCP request specific flags for manual dissection */
        if ((func == 0x57 || func == 0x59) && subfunc == 0x14 && ncp_tree && request_value) {
            request_value->req_mask = tvb_get_letohs(tvb, 8+4);
            request_value->req_mask_ext = tvb_get_letohs(tvb, 8+6);
        }
        /* NCP function 89/6 passes either ASCII or UTF8 data */
        /* Decode manually since it is not possible to SREC the request */
        /* packets from the python code */
        if (func == 0x59 && subfunc == 0x6) {
            dissect_ncp_89_6_request(tvb, ncp_tree, 22);
        }
        /*
         * Need to parse for Novell specific wildcard values in Search
         * Pattern, decode this ncp (89)/20 and (89)/03 req manually here.
         *
         * XXX - do 0x57/87 and 0x59/89 both have this?  87 doesn't
         * appear to have the ASCII/UTF-8 data type field.
         */
        if (ncp_rec->func == 0x59 && (ncp_rec->subfunc == 0x14 || ncp_rec->subfunc == 0x03)) {
            if (ncp_rec->subfunc == 0x03)
            {
                 dissect_ncp_8x20req(tvb, ncp_tree, 26, ncp_rec->func);
            }
/*if (ncp_rec->func == 0x57)
{
            dissect_ncp_8x20req(tvb, ncp_tree, 27, ncp_rec->func);
}*/
            else
            {
                dissect_ncp_8x20req(tvb, ncp_tree, 28, ncp_rec->func);
            }
        }
        /* Free the temporary proto_tree */
        CLEANUP_CALL_AND_POP_PFX(xx);

        /* Re-throw any exception. */
        if (exception_code != 0)
            THROW_MESSAGE(exception_code, message);
    }
}

static void
dissect_nds_ping_reply(tvbuff_t *tvb, packet_info *pinfo _U_,
                       proto_tree *ncp_tree, ncp_req_hash_value *request_value)
{
    uint8_t    ping_version;
    uint32_t   nds_string_len;
    uint32_t   nds_offset;
    uint32_t   bvalue;
    uint32_t   nds_flags;
    int        i;
    nstime_t   ns;

    ping_version = tvb_get_uint8(tvb, 8);
    proto_tree_add_item(ncp_tree, hf_ping_version, tvb, 8, 1, ENC_NA);
    if (ping_version == 9) {
        nds_string_len = tvb_get_ntohl(tvb, 9);
        nds_offset = nds_string_len+16;
        proto_tree_add_item(ncp_tree, hf_nds_tree_name, tvb, 16, nds_string_len, ENC_ASCII|ENC_NA);
        proto_tree_add_item(ncp_tree, hf_nds_reply_depth, tvb, nds_offset, 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(ncp_tree, hf_nds_reply_rev, tvb, (nds_offset+4), 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(ncp_tree, hf_nds_reply_flags, tvb, (nds_offset+8), 4, ENC_LITTLE_ENDIAN);
    }
    else {
        nds_offset = 12;
        nds_flags = request_value->req_nds_flags;
        bvalue = 0x00000001;

        for (i = 0 ; i < 32; i++ ) {
            if (nds_flags & bvalue)
            {
                switch(bvalue)
                {
                case 0x00000001:   /* Supported Fields */
                    proto_tree_add_bitmask(ncp_tree, tvb, nds_offset, hf_pingflags1, ett_ncp, ncp_pingflags1, ENC_LITTLE_ENDIAN);
                    nds_offset += 2;
                    proto_tree_add_bitmask(ncp_tree, tvb, nds_offset, hf_pingflags2, ett_ncp, ncp_pingflags2, ENC_LITTLE_ENDIAN);
                    nds_offset += 2;
                    break;
                case 0x00000002:
                    proto_tree_add_item(ncp_tree, hf_nds_reply_depth, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    break;
                case 0x00000004:
                    proto_tree_add_item(ncp_tree, hf_nds_reply_rev, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    break;
                case 0x00000008:
                    proto_tree_add_bitmask(ncp_tree, tvb, nds_offset, hf_pingpflags1, ett_ncp, ncp_pingpflags1, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    break;
                case 0x00000010:
                    proto_tree_add_bitmask(ncp_tree, tvb, nds_offset, hf_pingvflags1, ett_ncp, ncp_pingvflags1, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    break;
                case 0x00000020:
                    proto_tree_add_item(ncp_tree, hf_nds_letter_ver, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    break;
                case 0x00000040:
                    proto_tree_add_item(ncp_tree, hf_nds_os_majver, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_os_minver, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    proto_tree_add_item(ncp_tree, hf_ncp_os_revision, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    break;
                case 0x00000100:
                    proto_tree_add_item(ncp_tree, hf_nds_lic_flags, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
                    nds_offset += 4;
                    break;
                case 0x00000200:
                    ns.secs = tvb_get_letohl(tvb, nds_offset);
                    ns.nsecs = 0;
                    proto_tree_add_time(ncp_tree, hf_nds_ds_time, tvb, nds_offset, 4, &ns);
                    nds_offset += 4;
                    break;
                case 0x00000400:
                    ns.secs = tvb_get_letohl(tvb, nds_offset);
                    ns.nsecs = 0;
                    proto_tree_add_time(ncp_tree, hf_nds_svr_time, tvb, nds_offset, 4, &ns);
                    nds_offset += 4;
                    break;
                case 0x00000800:
                    ns.secs = tvb_get_letohl(tvb, nds_offset);
                    ns.nsecs = 0;
                    proto_tree_add_time(ncp_tree, hf_nds_crt_time, tvb, nds_offset, 4, &ns);
                    nds_offset += 4;
                    break;
                case 0x00010000:
                    if(tvb_get_uint8(tvb, nds_offset) == 0x00)
                    {
                        nds_offset += 2;
                    }
                    nds_string_len = tvb_get_letohl(tvb, nds_offset);
                    nds_offset += 4;
                    proto_tree_add_item(ncp_tree, hf_sap_name, tvb, nds_offset, nds_string_len, ENC_ASCII|ENC_NA);
                    nds_offset += nds_string_len;
                    nds_offset += align_4(tvb, nds_offset);
                    break;
                case 0x00020000:
                    if(tvb_get_uint8(tvb, nds_offset) == 0x00)
                    {
                        nds_offset += 2;
                    }
                    nds_string_len = tvb_get_letohl(tvb, nds_offset);
                    nds_offset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_tree_name, tvb, nds_offset, nds_string_len, ENC_ASCII|ENC_NA);
                    nds_offset += nds_string_len;
                    nds_offset += align_4(tvb, nds_offset);
                    break;
                case 0x00040000:
                    if(tvb_get_uint8(tvb, nds_offset) == 0x00)
                    {
                        nds_offset += 2;
                    }
                    nds_string_len = tvb_get_letohl(tvb, nds_offset);
                    nds_offset += 4;
                    proto_tree_add_item(ncp_tree, hf_os_name, tvb, nds_offset, nds_string_len, ENC_ASCII|ENC_NA);
                    nds_offset += nds_string_len;
                    nds_offset += align_4(tvb, nds_offset);
                    break;
                case 0x00080000:
                    if(tvb_get_uint8(tvb, nds_offset) == 0x00)
                    {
                        nds_offset += 2;
                    }
                    nds_string_len = tvb_get_letohl(tvb, nds_offset);
                    nds_offset += 4;
                    proto_tree_add_item(ncp_tree, hf_hardware_name, tvb, nds_offset, nds_string_len, ENC_ASCII|ENC_NA);
                    nds_offset += nds_string_len;
                    nds_offset += align_4(tvb, nds_offset);
                    break;
                case 0x00100000:
                    if(tvb_get_uint8(tvb, nds_offset) == 0x00)
                    {
                        nds_offset += 2;
                    }
                    nds_string_len = tvb_get_letohl(tvb, nds_offset);
                    nds_offset += 4;
                    proto_tree_add_item(ncp_tree, hf_vendor_name, tvb, nds_offset, nds_string_len, ENC_ASCII|ENC_NA);
                    nds_offset += nds_string_len;
                    nds_offset += align_4(tvb, nds_offset);
                    break;
                default:
                    break;
                }
            }
            bvalue = bvalue*2;
        }
    }
}

static void
dissect_nds_reply(tvbuff_t *tvb, packet_info *pinfo,
                  proto_tree *ncp_tree, uint32_t nds_error_code,
                  const char *nds_error_string, ncp_req_hash_value *request_value,
                  conversation_t *conversation)
{
    uint32_t                        nds_offset;
    proto_item                      *expert_item;
    const char                      *verb_string;
    bool                            resolve_eid=false;
    uint32_t                        global_eid=0;
    bool                            add_eid = false;
    char                            *global_object_name = NULL;
    ncp_req_eid_hash_value          *request_eid_value = NULL;
    nds_val                         temp_value;
    uint32_t                        class_def_type_val;

    nds_offset = 8;

    proto_tree_add_item(ncp_tree, hf_ncp_fragment_size, tvb, nds_offset,
                        4, ENC_LITTLE_ENDIAN);
    nds_offset += 4;
    proto_tree_add_item(ncp_tree, hf_ncp_fragment_handle, tvb, nds_offset,
                        4, ENC_LITTLE_ENDIAN);
    nds_offset += 4;
    /*
     * Is the possibly-reassembled reply large enough to have a completion
     * code?  (We can't check the fragment size as this might just be the
     * last fragment.)
     */
    if (tvb_reported_length_remaining(tvb, nds_offset) >= 4)
    {
        /* Yes - process the completion code. */
        expert_item = proto_tree_add_uint_format(ncp_tree, hf_nds_reply_error, tvb, nds_offset,
                                                 4, nds_error_code, "NDS Completion Code: 0x%08x, %s",
                                                 nds_error_code, nds_error_string);

        if (nds_error_code != 0 && ncp_echo_err) {
            expert_add_info_format(pinfo, expert_item, &ei_nds_reply_error, "NDS Error: 0x%08x %s", nds_error_code, nds_error_string);
        }
    }

    if ((request_value == NULL) || (nds_error_code != 0))
        return;

    nds_offset = 20;
    verb_string = val_to_str_const(request_value->nds_request_verb,
                                    ncp_nds_verb_vals, "Continuation Fragment");
    if(request_value->req_nds_prot_flags & 0x4000)
    {
        /* CRC is included in the NDS header so justify the offset */
        proto_tree_add_item(ncp_tree, hf_nds_crc, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;
    }

    if(request_value->nds_request_verb != 0)
    {
        proto_tree_add_uint_format_value(ncp_tree,
                                    hf_ncp_nds_verb, tvb, 6, 0,
                                    request_value->nds_request_verb,
                                    "%d, %s",
                                    request_value->nds_request_verb, verb_string);
    }

    memset(&temp_value, 0, sizeof(temp_value));
    switch (request_value->nds_request_verb)
    {
    case 0x01:
        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_tag_string, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN, &temp_value.vvalue);
        nds_offset += 4;

        switch(temp_value.vvalue)
        {
        case NDS_TAG_NO_SUCH_ENTRY:
            break;
        case NDS_TAG_LOCAL_ENTRY:
            proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN, &global_eid);
            add_eid = true;
            resolve_eid = true;
            global_object_name = request_value->object_name;
            nds_offset += 4;

            temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
            temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
            temp_value.vdesc = "Referral Records: %u";
            temp_value.vlength = 4;
            temp_value.voffset = nds_offset;
            temp_value.hfname = hf_nds_referrals;
            temp_value.mvtype = MVTYPE_LOC_ADDR_REFERRAL_REPLY;
            process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
            break;
        case NDS_TAG_REMOTE_ENTRY:
            nds_offset += 4;   /* UINT32 reserved field */
            proto_tree_add_item(ncp_tree, hf_nds_eid, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
            nds_offset += 4;
            temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
            temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
            temp_value.vdesc = "Referral Records: %u";
            temp_value.vlength = 4;
            temp_value.voffset = nds_offset;
            temp_value.hfname = hf_nds_referrals;
            temp_value.mvtype = MVTYPE_LOC_ADDR_REFERRAL_REPLY;
            process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
            break;
        case NDS_TAG_ALIAS_ENTRY:
            temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
            if (temp_value.vvalue == 0x00)
                break;

            temp_value.vstring =(const char*)tvb_get_string_enc(pinfo->pool, tvb, nds_offset+4, temp_value.vvalue, ENC_UTF_16|ENC_LITTLE_ENDIAN);
            proto_tree_add_string_format(ncp_tree, hf_nds_name, tvb, nds_offset, 4+temp_value.vvalue, temp_value.vstring, "Alias Name: %s", temp_value.vstring);
            break;
        case NDS_TAG_REFERRAL_INFORMATION:
            temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
            proto_tree_add_uint_format(ncp_tree, hf_nds_eid, tvb, nds_offset, 4, temp_value.vvalue, "Distance Object is From Root: 0x%08x", temp_value.vvalue);
            nds_offset += 4;

            temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
            temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
            temp_value.vdesc = "Referral Records: %u";
            temp_value.vlength = 4;
            temp_value.voffset = nds_offset;
            temp_value.hfname = hf_nds_referrals;
            temp_value.mvtype = MVTYPE_ADDR_REFERRAL_REPLY;
            process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
            break;
        case NDS_TAG_ENTRY_AND_REFERRALS:
            proto_tree_add_item(ncp_tree, hf_nds_result_flags, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
            nds_offset += 4;
            proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN, &global_eid);
            add_eid = true;
            resolve_eid = true;
            global_object_name = request_value->object_name;
            nds_offset += 4;

            temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
            temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
            temp_value.vdesc = "Referral Records: %u";
            temp_value.vlength = 4;
            temp_value.voffset = nds_offset;
            temp_value.hfname = hf_nds_referrals;
            temp_value.mvtype = MVTYPE_ADDR_REFERRAL_REPLY;
            process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
            break;
        default:
            break;
        }
        break;
    case 0x02:
        nds_offset -= 4;
        temp_value.vvalue = 1;
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Entry Information";
        temp_value.vlength = 0;
        temp_value.voffset = nds_offset;
        temp_value.hfname = hf_nds_name;
        temp_value.mvtype = MVTYPE_LIST_PARTITIONS;
        temp_value.vflags = request_value->req_nds_flags;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        break;
    case 0x03:
        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;
        proto_tree_add_item(ncp_tree, hf_nds_info_type, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;

        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Number of Attributes: %u";
        temp_value.vlength = 4;
        temp_value.voffset = nds_offset;
        temp_value.hfname = hf_nds_attr;
        temp_value.mvtype = MVTYPE_ATTR_REPLY;
        temp_value.vflags = request_value->req_nds_flags;
        temp_value.nds_version = request_value->nds_version;
        temp_value.pflags = request_value->req_nds_prot_flags;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        break;
    case 0x04:
        temp_value.vvalue = tvb_get_uint8(tvb, nds_offset);
        if (temp_value.vvalue == 0)
        {
            proto_tree_add_uint_format_value(ncp_tree, hf_nds_compare_results, tvb, nds_offset, 1, temp_value.vvalue, "Did Not Match");
        }
        else
        {
            proto_tree_add_uint_format_value(ncp_tree, hf_nds_compare_results, tvb, nds_offset, 1, temp_value.vvalue, "Matched");
        }
        break;
    case 0x05:
        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;

        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Entry Information";
        temp_value.vlength = 0;
        temp_value.voffset = nds_offset;
        temp_value.hfname = hf_nds_name;
        temp_value.mvtype = MVTYPE_LIST_PARTITIONS;
        temp_value.vflags = request_value->req_nds_flags;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        break;
    case 0x06:
    case 0x07:
    case 0x08:
    case 0x09:
    case 0x0a:
    case 0x0b:
    case 0x0c:
    case 0x0d:
    case 0x0e:
        break;
    case 0x0f:
        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;
        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_class_def_type, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN, &class_def_type_val);
        nds_offset += 4;

        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Class Definitions %u";
        temp_value.vlength = 0;
        temp_value.voffset = nds_offset;
        temp_value.hfname = hf_nds_classes;
        temp_value.mvtype = MVTYPE_CLASS_NAMES;
        temp_value.vflags = class_def_type_val;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        break;
    case 0x10:
    case 0x11:
        break;
    case 0x12:
        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;

        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Classes: %u";
        temp_value.vlength = 4;
        temp_value.voffset = nds_offset;
        temp_value.mvtype = MVTYPE_READ_CLASS_REQ;
        temp_value.hfname= hf_nds_classes;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        break;
    case 0x13:
        proto_tree_add_item(ncp_tree, hf_nds_privileges, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        break;
    case 0x14:
    case 0x15:
        break;
    case 0x16:
        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;

        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        if (temp_value.vvalue == 0)
            break;

        temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, nds_offset+4, temp_value.vvalue, ENC_UTF_16|ENC_LITTLE_ENDIAN);
        proto_tree_add_string_format(ncp_tree, hf_nds_name, tvb, nds_offset, 4+temp_value.vvalue, temp_value.vstring, "Server Distinguished Name: %s", temp_value.vstring);
        nds_offset += 4+temp_value.vvalue;
        nds_offset += align_4(tvb, nds_offset);

        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Replicas: %u";
        temp_value.vlength = 4;
        temp_value.voffset = nds_offset;
        temp_value.hfname = hf_nds_replicas;
        temp_value.mvtype = MVTYPE_READ_REPLICAS;
        temp_value.bit1 = "Output Flags";
        temp_value.bit2 = "Entry ID";
        temp_value.bit3 = "Replica State";
        temp_value.bit4 = "Modification Timestamp";
        temp_value.bit5 = "Purge Time";
        temp_value.bit6 = "Local Partition ID";
        temp_value.bit7 = "Distinguished Name";
        temp_value.bit8 = "Replica Type";
        temp_value.bit9 = "Partition Busy";
        temp_value.vflags = request_value->req_nds_flags;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        break;
    case 0x17:
    case 0x18:
    case 0x19:
    case 0x1a:
        break;
    case 0x1b:
        proto_tree_add_item(ncp_tree, hf_nds_file_handle, tvb, nds_offset, 4, ENC_BIG_ENDIAN);
        nds_offset += 4;
        proto_tree_add_item(ncp_tree, hf_nds_file_size, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        break;
    case 0x1c:
    case 0x1d:
    case 0x1e:
    case 0x1f:
    case 0x20:
    case 0x21:
    case 0x22:
    case 0x23:
    case 0x24:
    case 0x25:
    case 0x26:
    case 0x27:
    case 0x28:
    case 0x29:
    case 0x2a:
    case 0x2b:
    case 0x2c:
    case 0x2d:
    case 0x2e:
    case 0x2f:
    case 0x30:
    case 0x31:
    case 0x32:
    case 0x33:
    case 0x34:
        break;
    case 0x35:
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Server Name";
        temp_value.mvtype = MVTYPE_PROCESS_TAGS;
        temp_value.vflags = request_value->req_nds_flags;
        temp_value.hfname = hf_nds_svr_dst_name;
        temp_value.vlength = tvb_get_letohl(tvb, nds_offset);
        if (temp_value.vlength == 0x00)
            break;

        temp_value.voffset = nds_offset;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        nds_offset += temp_value.vlength + 4;
        nds_offset += align_4(tvb, nds_offset);

        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
        temp_value.vdesc = "Referral Records: %u";
        temp_value.vlength = 4;
        temp_value.voffset = nds_offset;
        temp_value.hfname = hf_nds_referrals;
        temp_value.mvtype = MVTYPE_LOC_ADDR_REFERRAL_REPLY;
        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
        break;
    case 0x36:
    case 0x37:
    case 0x38:
        break;
    case 0x39:
        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN, &global_eid);
        add_eid = true;
        resolve_eid = true;
        global_object_name = request_value->object_name;
        break;
    case 0x3a:
    case 0x3b:
    case 0x3c:
    case 0x3d:
    case 0x3e:
    case 0x3f:
    case 0x40:
    case 0x41:
    case 0x42:
    case 0x43:
    case 0x44:
    case 0x45:
    case 0x46:
    case 0x47:
    case 0x48:
    case 0x49:
    case 0x4a:
    case 0x4b:
    case 0x4c:
    case 0x4d:
        break;
    case 0x6e:
        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN);
        nds_offset += 4;
        expert_item = proto_tree_add_item_ret_uint(ncp_tree, hf_iter_completion_code, tvb, nds_offset, 4, ENC_LITTLE_ENDIAN, &temp_value.vvalue);
        nds_offset += 4;

        if (temp_value.vvalue != 0 && ncp_echo_err) {
            expert_add_info_format(pinfo, expert_item, &ei_nds_iteration, "NDS Iteration Error: 0x%08x %s",
                                    temp_value.vvalue, val_to_str(temp_value.vvalue, nds_reply_errors, "Unknown: %d"));
        }
        temp_value.vvalue = tvb_get_letohl(tvb, nds_offset);
        temp_value.vtype = VTYPE_ITEM;
        temp_value.vlength = 4;
        temp_value.voffset = nds_offset;
        temp_value.mvtype = MVTYPE_PROCESS_ITERATOR;
        temp_value.hfname = hf_ncp_nds_iterverb;
        dissect_nds_iterator(ncp_tree, tvb, pinfo, temp_value.vvalue, 0, nds_offset, false);
        break;
    default:
        break;
    }
    /* NDS Entry ID's (EID) is identified in the reply
        * packet of an NDS resolve name. We need to store
        * this EID and its associated name into our hash
        * so that we can resolve the name for other NDS
        * requests. */
    if (!pinfo->fd->visited) {
        if(add_eid)
        {
            request_eid_value = ncp_eid_hash_lookup(conversation, global_eid);
            if (!request_eid_value) {
                request_eid_value = ncp_eid_hash_insert(global_eid);
                if (global_object_name != NULL)
                    (void) g_strlcpy(request_eid_value->object_name, global_object_name, 256);
                else
                    request_eid_value->object_name[0] = '\0';
            }
        }
    }
    /* Echo EID data to expert Chat window */
    if (add_eid && nds_echo_eid) {
        expert_add_info_format(pinfo, NULL, &ei_ncp_eid,
                                "EID (%08x) = %s", global_eid, global_object_name);
    }
    /* For NDS requests with just an EID, resolve name
        * from hash table. */
    if(resolve_eid)
    {
        request_eid_value = ncp_eid_hash_lookup(conversation, global_eid);
        if (request_eid_value) {
            proto_tree_add_string_format(ncp_tree,
                                            hf_nds_name, tvb, 6, 0,
                                            request_eid_value->object_name,
                                            "NDS Name for EID - %s",
                                            request_eid_value->object_name);
        }
    }
}

void
dissect_ncp_reply(tvbuff_t *tvb, packet_info *pinfo,
                  uint32_t nw_connection, uint8_t sequence, uint16_t type,
                  proto_tree *ncp_tree, struct novell_tap *ncp_tap)
{
    conversation_t      *conversation = NULL;
    ncp_req_hash_value  *request_value = NULL;
    const ncp_record    *ncp_rec = NULL;
    bool                *req_cond_results;
    uint8_t              completion_code=0;
    ptvcursor_t         *ptvc = NULL;
    const char          *error_string;
    uint32_t             nds_error_code = 0;
    /*uint32_t             nds_reply_buffer = 0;*/
    const char          *nds_error_string = NULL;
    /*uint32_t             nds_frag=0;*/
    proto_item          *expert_item;
    uint8_t              conn_stat;


#ifdef FAKE_TREE_IS_VISIBLE
    if (ncp_tree) {
        PTREE_DATA(ncp_tree)->visible=1;
    }
#endif

    if (!pinfo->fd->visited) {
        /* Find the conversation whence the request would have come. */
        conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                         CONVERSATION_NCP, nw_connection, nw_connection, 0);
        if (conversation != NULL) {
            /* find the record telling us the request made that caused
               this reply */
            request_value = ncp_hash_lookup(conversation, sequence, pinfo->num);
            if (request_value) {
                ncp_rec = request_value->ncp_rec;
            }
            p_add_proto_data(wmem_file_scope(), pinfo, proto_ncp, 0, (void*) request_value);
        }
        /* else... we haven't seen an NCP Request for that conversation
           and sequence.
           Create Service request packets do not contain nw_connection.
           The initial value is set to 65535 or 0. The reply packet has the
           valid connection. So, we can't find the request packet in
           our conversation list. To trap for this we can just perform
           the search again with 65535 to see if we can locate the
           proper request packet. */
        else {
            conversation = find_conversation(pinfo->num,
                                             &pinfo->src, &pinfo->dst, CONVERSATION_NCP, 65535, 65535, 0);
            if (conversation != NULL) {
                /* find the record telling us the request made
                   that caused this reply */
                request_value = ncp_hash_lookup(conversation,
                                                sequence, pinfo->num);
                if (request_value) {
                    ncp_rec = request_value->ncp_rec;
                }
                p_add_proto_data(wmem_file_scope(), pinfo, proto_ncp, 0,
                                 (void*) request_value);
            }
            else {
                conversation = find_conversation(pinfo->num,
                                                 &pinfo->src, &pinfo->dst, CONVERSATION_NCP, 0, 0, 0);
                if (conversation != NULL) {
                    /* find the record telling us the request made
                       that caused this reply */
                    request_value = ncp_hash_lookup(conversation,
                                                    sequence, pinfo->num);
                    if (request_value) {
                        ncp_rec = request_value->ncp_rec;
                    }
                    p_add_proto_data(wmem_file_scope(), pinfo, proto_ncp, 0,
                                     (void*) request_value);
                }
                /* else... we haven't seen an NCP Request for that
                   conversation and sequence. */
            }
        }
    }
    else {
        /*request_value = p_get_proto_data(wmem_file_scope(), pinfo, proto_ncp);*/
        conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                         CONVERSATION_NCP, nw_connection, nw_connection, 0);
        if (conversation != NULL) {

             request_value = ncp_hash_lookup(conversation,
                               sequence, pinfo->num);
        }
        if (request_value) {
            ncp_rec = request_value->ncp_rec;
        }
    }

    /*
     * Tap the packet before the dissectors are called so we
     * still get the tap listener called even if there is an
     * exception.
     */
    tap_queue_packet(ncp_tap->stat, pinfo, request_value);

    if (ncp_rec && ncp_rec->func==0x68 &&
        (ncp_rec->subfunc==0x02 || ncp_rec->subfunc==0x01)) {
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDS");
    }

    /* A completion code of 0 always means OK. Non-zero means failure,
     * but each non-zero value has a different meaning. And the same value
     * can have different meanings, depending on the ncp.func (and ncp.subfunc)
     * value. */
    completion_code = tvb_get_uint8(tvb, 6);
    if (completion_code == 0) {
        if(type == NCP_POSITIVE_ACK)
        {
            error_string = "Server Busy, Request Being Processed";
        }
        else
        {
            error_string = "OK";
        }
    } else {
        if (ncp_rec && ncp_rec->errors) {
            error_string = ncp_error_string(ncp_rec->errors, completion_code);
        }
        else {
            error_string = "Original Request Packet not Found";
        }
    }
    if (type == NCP_SERVICE_REPLY && ncp_rec && ncp_rec->func==0x68 &&
        ncp_rec->subfunc==0x02 && (tvb_reported_length_remaining(tvb, 8) >= 8))
    {
        uint32_t nds_offset;

        nds_offset = 8;
        /*nds_reply_buffer = tvb_get_letohl(tvb, nds_offset);*/
        nds_offset += 4;
        /*nds_frag = tvb_get_letohl(tvb, nds_offset);*/
        nds_offset += 4;
        /*
         * Is the possibly-reassembled reply large enough to have
         * a completion code?  (We can't check the fragment size
         * as this might just be the last fragment.)
         */
        if (tvb_reported_length_remaining(tvb, nds_offset) >= 4)
        {
            /* Yes - process the completion code. */
            nds_error_code = tvb_get_letohl(tvb, nds_offset);
            nds_error_string = val_to_str_const(nds_error_code, nds_reply_errors, "NDS Error - No Definition Found");
        }
    }
    col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
                    type == NCP_SERVICE_REPLY ? "R" : "ACK",
                    nds_error_string ? nds_error_string : error_string);

    if (ncp_tree) {

        if (request_value) {
            nstime_t ns;

            proto_tree_add_uint(ncp_tree, hf_ncp_req_frame_num, tvb, 0, 0,
                                request_value->req_frame_num);
            nstime_delta(&ns, &pinfo->abs_ts, &request_value->req_frame_time);
            proto_tree_add_time(ncp_tree, hf_ncp_req_frame_time, tvb, 0, 0, &ns);
        }

        /* Put the func (and maybe subfunc) from the request packet
         * in the proto tree, but hidden. That way filters on ncp.func
         * or ncp.subfunc will find both the requests and the replies.
         */
        if (ncp_rec) {
            proto_tree_add_uint_format_value(ncp_tree, hf_ncp_func, tvb, 6, 0,
                                       ncp_rec->func, "%u (0x%02X), %s",
                                       ncp_rec->func, ncp_rec->func, ncp_rec->name);
            if (ncp_requires_subfunc(ncp_rec->func)) {
                proto_tree_add_uint(ncp_tree, hf_ncp_subfunc, tvb, 6, 0, ncp_rec->subfunc);
            }
        }
    }

    expert_item = proto_tree_add_uint_format_value(ncp_tree, hf_ncp_completion_code, tvb, 6, 1,
                                             completion_code, "%d (0x89%02x), %s",
                                             completion_code, completion_code, error_string);
    if ((completion_code != 0 || type == NCP_POSITIVE_ACK) && ncp_echo_err) {
        expert_add_info_format(pinfo, expert_item, &ei_ncp_completion_code,
                               "Error: %d (0x89%02x) %s", completion_code,
                               completion_code, error_string);
    }

    conn_stat = tvb_get_uint8(tvb, 7);
    expert_item = proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb,
                                      7, 1, ENC_NA);
    if (conn_stat != 0 && conn_stat != 0x40 ) {
        col_set_str(pinfo->cinfo, COL_INFO,
                    "Error: Bad Connection Status");
        if (ncp_echo_err) {
            expert_add_info(pinfo, expert_item, &ei_ncp_connection_status);
        }
        return;
    }
    /*
     * Unless this is a successful reply, that's all there
     * is to parse.
     */
    if (type != NCP_SERVICE_REPLY || completion_code != 0)
        return;

    if (ncp_rec) {
        /* Dissect SSS Reply packets */
        if (ncp_rec->func == 0x5c && request_value)
        {
            dissect_sss_reply(tvb, pinfo, ncp_tree, ncp_rec->subfunc, request_value);
        }
        /* Dissect NMAS Reply packets */
        if (ncp_rec->func == 0x5e && request_value)
        {
            dissect_nmas_reply(tvb, pinfo, ncp_tree, ncp_rec->func, ncp_rec->subfunc, request_value);
        }
        /* Dissect NDS Ping packets */
        if (ncp_rec->func == 0x68 && ncp_rec->subfunc == 0x01)
        {
            dissect_nds_ping_reply(tvb, pinfo, ncp_tree,
                                   request_value);
        }
        /* Dissect NDS Reply packets */
        if (ncp_rec->func == 0x68 && ncp_rec->subfunc == 0x02)
        {
            dissect_nds_reply(tvb, pinfo, ncp_tree, nds_error_code,
                              nds_error_string, request_value, conversation);
        }
        /* Due to lack of group repeat fields in reply structure, decode this ncp 87/20 reply manually here. */
        if ((ncp_rec->func == 0x57 || ncp_rec->func == 0x59) && ncp_rec->subfunc == 0x14) {
            dissect_ncp_8x20reply(tvb, pinfo, ncp_tree, ncp_rec, request_value);
        }
        if (ncp_rec->func == 5 && ncp_echo_conn) {
            expert_add_info(pinfo, NULL, &ei_ncp_connection_destroyed);
        }
        if (ncp_rec->reply_ptvc) {
            /* If we're not building a protocol tree, quit;
             * "process_ptvc_record()" assumes we're building
             * a protocol tree, and we don't support putting
             * stuff in the Info column in replies, and no
             * state information is currently updated for
             * replies by "process_ptvc_record()", so we
             * can't, and don't have a reason to, dissect
             * any further if we're not building a protocol
             * tree. */
            if (!ncp_tree)
                return;

            /* If a non-zero completion code was found, it is
             * legal to not have any fields, even if the packet
             * type is defined as having fields.
             *
             * XXX - we already know that the completion code
             * is 0, as we checked it above.  Is there any
             * reason why we'd want to do a full dissection
             * if the completion code isn't 0? */
            if (completion_code != 0 && tvb_captured_length(tvb) == 8) {
                return;
            }

            /* Any request condition results? */
            if (request_value) {
                req_cond_results = request_value->req_cond_results;
            }
            else {
                req_cond_results = NULL;
            }
            clear_repeat_vars();
            ptvc = ptvcursor_new(pinfo->pool, ncp_tree, tvb, 8);
            process_ptvc_record(ptvc, pinfo, ncp_rec->reply_ptvc,
                                req_cond_results, true, ncp_rec, false);
            ptvcursor_free(ptvc);

            /* Process ncp 123/17 address records manually to format correctly. */
            if (ncp_rec->func == 0x7b && ncp_rec->subfunc == 0x11) {
                dissect_ncp_123_17_reply(tvb, pinfo, ncp_tree);
            }
            /* Process ncp 123/11 NLM names manually to format correctly. */
            if (ncp_rec->func == 0x7b && ncp_rec->subfunc == 0x0b && request_value) {
                dissect_ncp_123_11_reply(tvb, ncp_tree, request_value);
            }
            /* Process ncp 123/62 server set parameter values manually to format correctly. */
            if (ncp_rec->func == 0x7b && ncp_rec->subfunc == 0x3e) {
                dissect_ncp_123_62_reply(tvb, ncp_tree);
            }
            /* Process ncp 23/26 address records manually to format correctly. */
            if (ncp_rec->func == 0x17 && ncp_rec->subfunc == 0x1a) {
                dissect_ncp_23_26_reply(tvb, ncp_tree);
            }
            /* Process ncp 87/72 bytes transferred value. */
            if (ncp_rec->func == 0x57 && ncp_rec->subfunc == 0x48) {
                dissect_ncp_87_72_reply(tvb, ncp_tree);
            }

        }
    } else {
        if (tvb_reported_length(tvb) > 8) {
            expert_item = proto_tree_add_item(ncp_tree, hf_no_request_record_found, tvb, 8, -1, ENC_NA);
            if (ncp_echo_err) {
                expert_add_info(pinfo, expert_item, &ei_ncp_no_request_record_found);
            }
        }
    }
}

void
dissect_nds_request(tvbuff_t *tvb, packet_info *pinfo,
                    uint32_t nw_connection, uint8_t sequence,
                    uint16_t type, proto_tree *ncp_tree)
{
    uint8_t                  func, subfunc;
    ncp_req_hash_value      *request_value = NULL;
    ncp_req_eid_hash_value  *request_eid_value = NULL;
    const ncp_record        *ncp_rec = NULL;
    conversation_t          *conversation;
    ptvcursor_t             *ptvc = NULL;
    proto_tree              *temp_tree = NULL;
    bool                     run_req_cond = false;
    uint8_t                  nds_verb = 0;
    const char              *verb_string = "";
    uint32_t                 nds_frag = 0;
    uint8_t                  nds_version = 0;
    uint32_t                 foffset = 0;
    const char*              global_object_name = NULL;
    uint32_t                 global_eid=0;
    bool                     resolve_eid=false;
    uint32_t                 global_flags;
    uint32_t                 version, value1;
    nds_val                  temp_value;

    func = tvb_get_uint8(tvb, 6);
    subfunc = tvb_get_uint8(tvb, 7);

    ncp_rec = ncp_record_find(func, subfunc);
    if (ncp_rec) {
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDS");
    } else {
        col_add_fstr(pinfo->cinfo, COL_INFO,
                        "C Unknown Function %d (0x%02x)",
                        func, func);
    }

    /* Check to see if this is a fragment packet */
    nds_frag = tvb_get_letohl(tvb, 8);

    /* Keep track of the address and connection whence the request
       came, and the address and connection to which the request
       is being sent, so that we can match up calls with replies.
       (We don't include the sequence number, as we may want
       to have all packets over the same connection treated
       as being part of a single conversation so that we can
       let the user select that conversation to be displayed.) */

    conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                     CONVERSATION_NCP, nw_connection, nw_connection, 0);
    if (conversation == NULL) {
        /* It's not part of any conversation - create a new one. */
        conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
                                        CONVERSATION_NCP, nw_connection, nw_connection, 0);
    }

    if (!pinfo->fd->visited) {
        request_value = ncp_hash_insert(conversation, sequence, ncp_rec, pinfo->num);
        request_value->req_frame_num = pinfo->num;
        request_value->req_frame_time=pinfo->abs_ts;

        /* If this is the first time we're examining the packet,
         * check to see if this NCP type uses a "request condition".
         * If so, we have to build a proto_tree because request conditions
         * use display filters to work, and without a proto_tree,
         * display filters can't possibly work. If we already have
         * a proto_tree, then wonderful. If we don't, we need to build
         * one. */
        if (ncp_rec && !ncp_tree) {
            run_req_cond = true;
        }
        /* Keep track of the Fragment number in the request for defrag logic */
        request_value->nds_frag_num = nds_frag;
    }

    /* If we have to handle a request condition, or have to
       add to the Info column, we need to construct a protocol
       tree.  If we already have a proto_tree, then wonderful.
       If we don't, we need to build one. */
    if (run_req_cond && !ncp_tree) {
        proto_item *ti;

        temp_tree = proto_tree_create_root(pinfo);
        proto_tree_set_visible(temp_tree, false);
        ti = proto_tree_add_item(temp_tree, proto_ncp, tvb, 0, -1, ENC_NA);
        ncp_tree = proto_item_add_subtree(ti, ett_ncp);
    }

    /* Get NDS Verb */
    if (nds_frag == 0xffffffff) {
        /* First fragment or only fragment. */
        nds_verb = tvb_get_uint8(tvb, 24);
        if (nds_verb == 0xfe)
        {
            nds_version = nds_verb;
            nds_verb = tvb_get_uint8(tvb, 32);
            foffset = 36;
        }
        else
        {
            nds_version = 0;
            foffset = 28;
        }
        if (type == NCP_SERVICE_REQUEST) {
            proto_tree_add_item(ncp_tree, hf_nds_buffer_size, tvb, foffset,
                                4, ENC_LITTLE_ENDIAN);
            if (!pinfo->fd->visited) {
                /*
                 * Should we just do a lookup above, so that we use
                 * the value we created and added on the first pass,
                 * and fetch that value on the next pass?
                 */
                request_value = ncp_hash_lookup(conversation, sequence, pinfo->num);
                if (request_value != NULL) {
                    request_value->nds_request_verb = nds_verb;
                    request_value->nds_version = nds_version;
                }
            }
        }
        foffset = foffset+4;
        verb_string = val_to_str_const(nds_verb, ncp_nds_verb_vals,
                                       "Continuation Fragment");

        if (ncp_rec)
            col_add_fstr(pinfo->cinfo, COL_INFO, "C NDS %s", verb_string);
    } else {
        if (ncp_rec)
            col_add_fstr(pinfo->cinfo, COL_INFO, "C Continue NDS Fragment 0x%08x", nds_frag);
    }

    if (ncp_tree) {
        /* If the dissection throws an exception, be sure to free
         * the temporary proto_tree that was created. Because of the
         * way the CLEANUP_PUSH macro works, we can't put it in an 'if'
         * block; it has to be in the same scope as the terminating
         * CLEANUP_POP or CLEANUP_POP_AND_ALLOC. So, we always
         * call CLEANUP_POP and friends, but the value of temp_tree is
         * NULL if no cleanup is needed, and non-null if cleanup is needed.
         */
        CLEANUP_PUSH(free_proto_tree, temp_tree);

#ifdef FAKE_TREE_IS_VISIBLE
        PTREE_DATA(ncp_tree)->visible=1;
#endif

        if (type == NCP_SERVICE_REQUEST) {
            memset(&temp_value, 0, sizeof(temp_value));
            request_value = ncp_hash_lookup(conversation, sequence, pinfo->num);

            if (ncp_rec && ncp_rec->request_ptvc)
            {
                ptvc = ptvcursor_new(pinfo->pool, ncp_tree, tvb, 7);
                clear_repeat_vars();
                process_ptvc_record(ptvc, pinfo, ncp_rec->request_ptvc, NULL, true, ncp_rec, true);
                ptvcursor_free(ptvc);
            }
            if (ncp_tree) {
                proto_tree_add_uint_format_value(ncp_tree, hf_ncp_func, tvb, 6, 1,
                                           func, "%d (0x%02X), %s",
                                           func, func, ncp_rec ? ncp_rec->name : "Unknown");

                proto_tree_add_uint(ncp_tree, hf_ncp_subfunc, tvb, 7, 1, subfunc);

                proto_tree_add_uint(ncp_tree, hf_ncp_fragment_handle, tvb, 8, 4,
                                    nds_frag);
            }

            if (nds_frag == 0xffffffff) {
                uint32_t nds_prot_flags;

                if (ncp_tree) {
                    proto_tree_add_item(ncp_tree, hf_ncp_fragment_size, tvb, 12, 4, ENC_LITTLE_ENDIAN);

                    proto_tree_add_item(ncp_tree, hf_ncp_message_size, tvb, 16, 4, ENC_LITTLE_ENDIAN);
                }
                nds_prot_flags=tvb_get_letohs(tvb, 22);
                if (!pinfo->fd->visited) {
                    if (request_value)
                        request_value->req_nds_prot_flags = nds_prot_flags;
                }
                if (ncp_tree) {
                    proto_tree_add_bitmask(ncp_tree, tvb, 22, hf_ncp_nds_flag, ett_ncp, ndsprotflags, ENC_LITTLE_ENDIAN);

                    if (nds_version == 0) {
                        proto_tree_add_uint_format_value(ncp_tree, hf_ncp_nds_verb, tvb, 24, 4,
                                                nds_verb, "%d, (0x%02x), %s",
                                                nds_verb, nds_verb, verb_string);
                    }
                    else {
                        proto_tree_add_uint_format_value(ncp_tree, hf_ncp_nds_verb, tvb, 32, 4,
                                                nds_verb, "%d, (0x%02x), %s",
                                                nds_verb, nds_verb, verb_string);
                    }
                }

                switch(nds_verb) {

                case 0x01:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_nflags, ett_ncp, ncp_nflags, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    if (version == 0 || version == 1)
                    {
                        proto_tree_add_item(ncp_tree, hf_nds_scope, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                        value1 = tvb_get_letohl(tvb, foffset);
                        if (value1 == 0)
                            break;

                        global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                        proto_tree_add_string(ncp_tree, hf_nds_name, tvb, foffset, 4+value1, global_object_name);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                        if (!pinfo->fd->visited) {
                            if (request_value)
                                (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                        }
                        foffset += 4+value1;
                        foffset += align_4(tvb, foffset);

                        temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                        temp_value.vdesc = "Communications Transports: %u";
                        temp_value.vlength = 4;
                        temp_value.hfname= hf_nds_comm_trans;
                        temp_value.voffset = foffset;
                        temp_value.mvtype = MVTYPE_ADDR_REFERRAL_REQUEST;
                        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                        foffset = foffset + (temp_value.vvalue * 4) + 4;

                        temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                        temp_value.vdesc = "Tree Walker Transport Type: %u";
                        temp_value.hfname= hf_nds_tree_trans;
                        temp_value.voffset = foffset;
                        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                    }
                    else
                    {
                        proto_tree_add_item(ncp_tree, hf_min_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;

                        temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                        temp_value.vdesc = "Number of Versions to Include: %u";
                        temp_value.vlength = 4;
                        temp_value.mvtype = MVTYPE_ATTR_REQUEST2;
                        temp_value.voffset = foffset;
                        temp_value.hfname= hf_nds_ver_include;
                        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                        foffset += (temp_value.vvalue * 4) + 4;

                        temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                        temp_value.vdesc = "Number of Versions to Exclude: %u";
                        temp_value.hfname= hf_nds_ver_exclude;
                        temp_value.voffset = foffset;
                        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                        foffset += (temp_value.vvalue * 4) + 4;

                        proto_tree_add_item(ncp_tree, hf_nds_dn_output_type, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                        proto_tree_add_item(ncp_tree, hf_nds_nested_output_type, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;

                        value1 = tvb_get_letohl(tvb, foffset);
                        global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                        proto_tree_add_string(ncp_tree, hf_nds_output_delimiter, tvb, foffset, 4+value1, global_object_name);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                        if (!pinfo->fd->visited) {
                            if (request_value)
                                (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                        }
                        foffset += 4+value1;
                        foffset += align_4(tvb, foffset);

                        temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                        temp_value.vdesc = "Size of Entry Specifier: %u";
                        temp_value.mvtype = MVTYPE_PROC_ENTRY_SPECIFIERS;
                        temp_value.hfname= hf_nds_output_entry_specifier;
                        temp_value.voffset = foffset;
                        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                    }
                    break;
                case 0x02:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    switch(version)
                    {
                    case 0:
                        proto_tree_add_item(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        break;
                    case 1:
                        proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_rflags, ett_ncp, ncp_rflags, ENC_LITTLE_ENDIAN);
                        value1 = tvb_get_letohl(tvb, foffset);

                        if ((value1 & 0xf000) == 0xc000)
                        {
                            proto_tree_add_string(ncp_tree, hf_nds_name_type, tvb, 0, 0, "Partial");
                        }
                        else
                        {
                            proto_tree_add_string(ncp_tree, hf_nds_name_type, tvb, 0, 0, "Full");
                        }
                        foffset += 4;

                        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                        resolve_eid = true;
                        break;
                    case 2:
                        proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_rflags, ett_ncp, ncp_rflags, ENC_LITTLE_ENDIAN);
                        value1 = tvb_get_letohl(tvb, foffset);
                        if ((value1 & 0xf000) == 0xc000)
                        {
                            proto_tree_add_string(ncp_tree, hf_nds_name_type, tvb, 0, 0, "Return Partition Name");
                        }
                        else
                        {
                            proto_tree_add_string(ncp_tree, hf_nds_name_type, tvb, 0, 0, "Return Full Name");
                        }
                        foffset += 4;
                        proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_retinfoflagsl, ett_ncp, ncp_infoflagsl, ENC_LITTLE_ENDIAN);
                        global_flags = tvb_get_letohl(tvb, foffset);
                        if (!pinfo->fd->visited) {
                            if (request_value)
                                request_value->req_nds_flags = global_flags;
                        }
                        foffset += 2;
                        proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_retinfoflagsh, ett_ncp, ncp_infoflagsh, ENC_LITTLE_ENDIAN);
                        foffset += 2;

                        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                        resolve_eid = true;
                        break;
                    default:
                        break;
                    }
                    break;

                case 0x03:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;

                    if (version == 0)
                    {
                        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                        resolve_eid = true;
                        foffset += 4;
                        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_info_type, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_flags);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", rval_to_str_const(global_flags, nds_info_type, "No Info Type Set"));
                        if (!pinfo->fd->visited) {
                            if (request_value)
                                request_value->req_nds_flags = global_flags;
                        }

                        foffset += 4;
                        proto_tree_add_item(ncp_tree, hf_nds_all_attr, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;

                        temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                        temp_value.vdesc = "Attributes: %u";
                        temp_value.vlength = 4;
                        temp_value.voffset = foffset;
                        temp_value.mvtype = MVTYPE_ATTR_REQUEST;
                        temp_value.hfname= hf_nds_attr;
                        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", temp_value.vstring);
                    }
                    else
                    {
                        proto_tree_add_item(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                        resolve_eid = true;
                        foffset += 4;
                        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_info_type, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_flags);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", rval_to_str_const(global_flags, nds_info_type, "No Info Type Set"));
                        if (!pinfo->fd->visited) {
                            if (request_value)
                                request_value->req_nds_flags = global_flags;
                        }
                        foffset += 4;
                        proto_tree_add_item(ncp_tree, hf_nds_all_attr, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;

                        temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                        temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                        temp_value.vdesc = "Attributes: %u";
                        temp_value.vlength = 4;
                        temp_value.voffset = foffset;
                        temp_value.mvtype = MVTYPE_ATTR_REQUEST;
                        temp_value.hfname= hf_nds_attr;
                        process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " %s", temp_value.vstring);
                   }
                   break;
                case 0x04:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;

                    if (version == 1)
                    {
                        /* Version 1 specifies for this offset value to always be a value of 1*/
                        /* No need to display to user */
                        foffset += 4;
                    }

                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    foffset += 4;

                    foffset += 4;       /* Attribute Count = 1 */

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string_format(ncp_tree, hf_nds_name, tvb, foffset, 4+value1, global_object_name, "Attribute Name Being Compared: %s", global_object_name);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                    }
                    foffset += 4+value1;
                    foffset += align_4(tvb, foffset);

                    foffset += 4;       /* Attribute Count = 1 */

                    value1 = tvb_get_letohl(tvb, foffset);
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string_format(ncp_tree, hf_value_string, tvb, foffset, 4+value1, temp_value.vstring, "Attribute Value: %s", temp_value.vstring);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " %s", temp_value.vstring);
                    break;
                case 0x05:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_rflags, ett_ncp, ncp_lflags, ENC_LITTLE_ENDIAN);
                    foffset += 2;
                    /*
                     * XXX - what are the two bytes following the rflags?
                     * Or is it a 4-byte field?
                     */
                    foffset += 2;
                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_parent, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    if (tvb_reported_length_remaining(tvb, foffset) == 0) {
                        /*
                         * Some requests appear to stop here.
                         *
                         * XXX - we test for version == 0 later; do all
                         * version 0 requests stop here, rather than
                         * after the name filter, or do some stop here
                         * and some stop there?  If the latter, is there
                         * some other way of determining whether the
                         * request stops here?
                         */
                        if (!pinfo->fd->visited) {
                            /*
                             * This appears to be the set of fields
                             * provided in responses to requests that
                             * stop before providing a list of requested
                             * fields.
                             *
                             * XXX - is the last entry really the Relative
                             * Distinguished Name?  In the captures I've
                             * seen with short requests, it begins with
                             * "CN=", unlike the captures I've seen with
                             * long requests, where it doesn't have that
                             * prefix.
                             */
                            if (request_value)
                                request_value->req_nds_flags =
                                    DSI_ENTRY_ID|DSI_ENTRY_FLAGS|DSI_SUBORDINATE_COUNT|DSI_MODIFICATION_TIME|DSI_BASE_CLASS|DSI_ENTRY_RDN;
                        }
                        break;
                    }

                    if (!pinfo->fd->visited) {
                        if (request_value)
                            request_value->req_nds_flags = tvb_get_letohl(tvb, foffset);
                    }
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_retinfoflagsl, ett_ncp, ncp_infoflagsl, ENC_LITTLE_ENDIAN);
                    foffset += 2;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_retinfoflagsh, ett_ncp, ncp_infoflagsh, ENC_LITTLE_ENDIAN);
                    foffset += 2;

                    value1 = tvb_get_letohl(tvb, foffset);
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_name_filter, tvb, foffset, 4+value1, temp_value.vstring);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", temp_value.vstring);
                    foffset += 4+value1;
                    if (version == 0)
                        break;

                    foffset += align_4(tvb, foffset);

                    value1 = tvb_get_letohl(tvb, foffset);
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_class_filter, tvb, foffset, 4+value1, temp_value.vstring);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " %s", temp_value.vstring);
                    foffset += 4+value1;
                    if (version == 1)
                        break;

                    foffset += align_4(tvb, foffset);

                    temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                    temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                    temp_value.vdesc = "Seconds: %u";
                    temp_value.vlength = 4;
                    temp_value.mvtype = MVTYPE_PRINT_TIMESTAMP;
                    temp_value.hfname= hf_nds_time_filter;
                    temp_value.voffset = foffset;
                    process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                    break;
                case 0x06:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = false;
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_search_scope, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_num_objects, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_siflags, ett_ncp, ncp_siflags, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    if (version != 2)
                    {
                        proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_retinfoflagsl, ett_ncp, ncp_infoflagsl, ENC_LITTLE_ENDIAN);
                        foffset += 2;
                        proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_retinfoflagsh, ett_ncp, ncp_infoflagsh, ENC_LITTLE_ENDIAN);
                    }
                    break;
                case 0x07:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    if (version != 0)
                    {
                        proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                    }

                    global_eid = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_eid, tvb, foffset, 4, global_eid, "Parent Entry ID: 0x%08x", global_eid);
                    resolve_eid = false;
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;
                    global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_relative_dn, tvb, foffset, 4+value1, global_object_name);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                    }
                    foffset += 4+value1;
                    foffset += align_4(tvb, foffset);

                    temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                    temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                    temp_value.vstring = "";
                    temp_value.vdesc = "Attributes: %u";
                    temp_value.vlength = 4;
                    temp_value.voffset = foffset;
                    temp_value.mvtype = MVTYPE_ADD_ATTR_REQUEST;
                    temp_value.hfname= hf_nds_attr;
                    process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                    break;
                case 0x08:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    break;

                case 0x09:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;

                    if (version != 0)
                    {
                        proto_tree_add_item(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                    }

                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    foffset += 4;

                    temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                    temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                    temp_value.vstring = "";
                    temp_value.vdesc = "Number of Attributes to Change %u";
                    temp_value.vlength = 4;
                    temp_value.mvtype = MVTYPE_MODIFY_ATTR_REQUEST;
                    temp_value.hfname= hf_nds_number_of_changes;
                    temp_value.voffset = foffset;
                    process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                    break;
                case 0x0a:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    foffset += 4;

                    proto_tree_add_item(ncp_tree, hf_nds_keep, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    foffset += align_4(tvb, foffset);

                    value1 = tvb_get_letohl(tvb, foffset);
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_new_rdn, tvb, foffset, 4+value1, temp_value.vstring);
                    break;

                case 0x0b:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_acflags, ett_ncp, ncp_acflags, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;
                    global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string_format(ncp_tree, hf_nds_relative_dn, tvb, foffset, 4+value1, global_object_name, "Attribute Name: %s", global_object_name);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                    }
                    foffset += 4+value1;
                    foffset += align_4(tvb, foffset);

                    proto_tree_add_item(ncp_tree, hf_nds_syntax, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_lower, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_upper, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_asn1, tvb, foffset, value1, ENC_NA);
                    break;
                case 0x0c: /* Not Defined */
                    break;
                case 0x0d:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_attribute_dn, tvb, foffset, 4+value1, global_object_name);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                    }
                    break;
                case 0x0e: /* Not Defined */
                    break;
                case 0x0f:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_class_def_type, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                    {
                        proto_tree_add_uint_format_value(ncp_tree, hf_nds_return_all_classes, tvb, foffset, 4, value1, "Do Not Return All Classes");
                    }
                    else
                    {
                        proto_tree_add_uint_format_value(ncp_tree, hf_nds_return_all_classes, tvb, foffset, 4, value1, "Return All Classes");
                    }
                    foffset += 4;
                    foffset += align_4(tvb, foffset);

                    temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                    temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                    temp_value.vdesc = "Classes: %u";
                    temp_value.vlength = 4;
                    temp_value.mvtype = MVTYPE_READ_CLASS_REQ;
                    temp_value.hfname= hf_nds_classes;
                    temp_value.voffset = foffset;
                    process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                    break;
                case 0x10:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string_format(ncp_tree, hf_nds_base_class, tvb, foffset, 4+value1, global_object_name, "Class Name: %s", global_object_name);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                    }
                    foffset += 4+value1;
                    foffset += align_4(tvb, foffset);

                    temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                    temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                    temp_value.vdesc = "Number of Attributes to Add: %u";
                    temp_value.vlength = 4;
                    temp_value.voffset = foffset;
                    temp_value.mvtype = MVTYPE_MODIFY_CLASS;
                    temp_value.hfname= hf_nds_att_add;
                    break;
                case 0x11:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    global_object_name = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string_format(ncp_tree, hf_nds_base, tvb, foffset, 4+value1, global_object_name, "Class Name: %s", global_object_name);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", global_object_name);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            (void) g_strlcpy(request_value->object_name, global_object_name, 256);
                    }
                    break;
                case 0x12:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    break;
                case 0x13:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string_format(ncp_tree, hf_nds_name, tvb, foffset, 4+value1, temp_value.vstring, "Trustee Name: %s", temp_value.vstring);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", temp_value.vstring);
                    foffset += 4+value1;
                    foffset += align_4(tvb, foffset);

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string_format(ncp_tree, hf_nds_name, tvb, foffset, 4+value1, temp_value.vstring, "Attribute to be Checked: %s", temp_value.vstring);
                    foffset += 4+value1;
                    foffset += align_4(tvb, foffset);

                    if(version != 0)
                    {
                        value1 = tvb_get_letohl(tvb, foffset);
                        if (value1 == 0)
                            break;

                        temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                        proto_tree_add_string_format(ncp_tree, hf_nds_name, tvb, foffset, 4+value1, temp_value.vstring, "Security Equivalence: %s", temp_value.vstring);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " %s", temp_value.vstring);
                    }
                    break;
                case 0x14: /* Not Defined */
                case 0x15:
                    break;
                case 0x16:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_rflags, ett_ncp, nds_bitflags, ENC_LITTLE_ENDIAN);
                    foffset += 2;
                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    if(version == 0)
                    {
                        global_flags = 0x000000c0;
                        if (!pinfo->fd->visited) {
                            if (request_value)
                                request_value->req_nds_flags = global_flags;
                        }
                        break;
                    }

                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_l1flagsl, ett_ncp, ncp_l1flagsl, ENC_LITTLE_ENDIAN);
                    global_flags = tvb_get_letohs(tvb, foffset);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            request_value->req_nds_flags = global_flags;
                    }
                    foffset += 2;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_l1flagsh, ett_ncp, ncp_l1flagsh, ENC_LITTLE_ENDIAN);
                    foffset += 2;

                    if(version == 1)
                        break;

                    proto_tree_add_item(ncp_tree, hf_nds_partition_root_id, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    break;
                case 0x17:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, value1, "Flags: 0x%08x", value1);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_new_part_id, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    break;
                case 0x18:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, value1, "Flags: 0x%08x", value1);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_child_part_id, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    break;
                case 0x19:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, value1, "Flags: 0x%08x", value1);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_master_part_id, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_replica_type, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_target_name, tvb, foffset, 4+value1, temp_value.vstring);
                    break;
                case 0x1a: /* Not Defined */
                    break;
                case 0x1b:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_stream_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;

                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_stream_name, tvb, foffset, 4+value1, temp_value.vstring);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", temp_value.vstring);
                    break;
                case 0x1c: /* Not Defined */
                case 0x1d:
                case 0x1e:
                case 0x1f:
                case 0x20:
                case 0x21:
                case 0x22:
                case 0x23:
                case 0x24:
                case 0x25:
                    break;
                case 0x26:
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &version);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, value1, "Flags: 0x%08x", value1);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_time_delay, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    if(version == 0)
                    {
                        value1 = tvb_get_letohl(tvb, foffset);
                        if (value1 == 0)
                            break;

                        temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                        proto_tree_add_string(ncp_tree, hf_nds_root_name, tvb, foffset, 4+value1, temp_value.vstring);
                        col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", temp_value.vstring);
                    }
                    else
                    {
                        global_eid = tvb_get_letohl(tvb, foffset);
                        proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                        resolve_eid = true;
                    }
                    break;
                case 0x27: /* Not Defined */
                case 0x28:
                case 0x29:
                    break;
                case 0x2a:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_req_flags, tvb, foffset, 4, value1, "Flags: 0x%08x", value1);
                    foffset += 4;
                    global_eid = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_ver, tvb, foffset, 4, global_eid, "Destination Parent Entry ID: 0x%08x", global_eid);
                    resolve_eid = true;
                    foffset += 4;

                    value1 = tvb_get_letohl(tvb, foffset);
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_new_rdn, tvb, foffset, 4+value1, temp_value.vstring);
                    foffset += (4+value1);
                    foffset += align_4(tvb, foffset);

                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_target_name, tvb, foffset, 4+value1, temp_value.vstring);
                    break;
                case 0x2b:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_verb2b_req_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    global_eid = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_ver, tvb, foffset, 4, global_eid, "Source Entry ID: 0x%08x", global_eid);
                    resolve_eid = true;
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_ver, tvb, foffset, 4, value1, "Destination Parent Entry ID: 0x%08x", value1);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_new_rdn, tvb, foffset, 4+value1, temp_value.vstring);
                    foffset += (4+value1);
                    foffset += align_4(tvb, foffset);
                    value1 = tvb_get_letohl(tvb, foffset);
                    if (value1 == 0)
                        break;
                    temp_value.vstring = (const char*)tvb_get_string_enc(pinfo->pool, tvb, foffset+4, value1, ENC_UTF_16|ENC_LITTLE_ENDIAN);
                    proto_tree_add_string(ncp_tree, hf_nds_target_name, tvb, foffset, 4+value1, temp_value.vstring);
                    break;
                case 0x2c: /* Not Defined */
                case 0x2d:
                case 0x2e:
                case 0x2f:
                case 0x30:
                case 0x31:
                    break;
                case 0x32:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    value1 = tvb_get_letohl(tvb, foffset);
                    temp_value.vstring = val_to_str_const(value1, ncp_nds_verb_vals, "(No Verb Found)");
                    proto_tree_add_string_format(ncp_tree, hf_mv_string, tvb, foffset, 4+value1, temp_value.vstring, "NDS Verb: %s", temp_value.vstring);
                break;
                case 0x33: /* Not Defined */
                case 0x34:
                    break;
                case 0x35:
                    if (nds_version != 0)
                    {
                        proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                        foffset += 4;
                        proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_rflags, ett_ncp, ncp_rflags, ENC_LITTLE_ENDIAN);
                        global_flags = tvb_get_letohl(tvb, foffset);
                        if (!pinfo->fd->visited) {
                            if (request_value)
                                request_value->req_nds_flags = global_flags;
                        }
                    }
                    break;
                case 0x36: /* Not Defined */
                case 0x37:
                case 0x38:
                    break;
                case 0x39:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    break;
                case 0x3a:
                    proto_tree_add_item(ncp_tree, hf_nds_buffer_size, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    break;
                case 0x3b:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_item_ret_uint(ncp_tree, hf_nds_eid, tvb, foffset, 4, ENC_LITTLE_ENDIAN, &global_eid);
                    resolve_eid = true;
                    break;
                case 0x3c: /* Not Defined */
                case 0x3d:
                case 0x3e:
                case 0x3f:
                case 0x40:
                case 0x41:
                case 0x42:
                case 0x43:
                case 0x44:
                case 0x45:
                case 0x46:
                case 0x47:
                case 0x48:
                case 0x49:
                case 0x4a:
                case 0x4b:
                case 0x4c:
                case 0x4d:
                    break;
                case 0x6e:
                    proto_tree_add_item(ncp_tree, hf_nds_ver, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    proto_tree_add_bitmask(ncp_tree, tvb, foffset, hf_nds_rflags, ett_ncp, ncp_rflags, ENC_LITTLE_ENDIAN);
                    global_flags = tvb_get_letohl(tvb, foffset);
                    if (!pinfo->fd->visited) {
                        if (request_value)
                            request_value->req_nds_flags = global_flags;
                    }
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_iteration, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;
                    global_eid = tvb_get_letohl(tvb, foffset);
                    proto_tree_add_uint_format(ncp_tree, hf_nds_eid, tvb, foffset, 4, global_eid, "Base Entry ID: 0x%08x", global_eid);
                    resolve_eid = true;
                    foffset += 4;
                    proto_tree_add_item(ncp_tree, hf_nds_scope, tvb, foffset, 4, ENC_LITTLE_ENDIAN);
                    foffset += 4;

                    temp_value.vvalue = tvb_get_letohl(tvb, foffset);
                    temp_value.vtype = VTYPE_MULTIVALUE_UINT32;
                    temp_value.vdesc = "Iterator: 0x%08x";
                    temp_value.vlength = 4;
                    temp_value.voffset = foffset;
                    temp_value.hfname= hf_nds_iterator;
                    temp_value.mvtype = MVTYPE_PROCESS_ITERATOR;
                    process_multivalues(ncp_tree, tvb, pinfo, &temp_value);
                    col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", temp_value.vstring);
                    break;
                default: /* Not Defined */
                    break;
                }
            }

            /* For NDS requests with just an EID, resolve name from hash table. */
            request_eid_value = ncp_eid_hash_lookup(conversation, global_eid);
            if(resolve_eid) {
                if (request_eid_value) {
                    col_append_fstr(pinfo->cinfo, COL_INFO, ", Object Name - %s", request_eid_value->object_name);
                }
            }
        }

        /* Free the temporary proto_tree */
        CLEANUP_CALL_AND_POP;
    }
}

/*
 * XXX - this duplicates stuff in "dissect_ncp_request()"; could
 * "dissect_ncp_request()" not just call "dissect_ping_req()" if
 * the operation is an NCP ping, and "dissect_ping_req()" just dissect
 * ping portion?
 */
void
dissect_ping_req(tvbuff_t *tvb, packet_info *pinfo,
                 uint32_t nw_connection, uint8_t sequence,
                 uint16_t type, proto_tree *ncp_tree)
{
    uint8_t              func, subfunc = 0;
    ncp_req_hash_value  *request_value = NULL;
    const ncp_record    *ncp_rec = NULL;
    conversation_t      *conversation;
    ptvcursor_t         *ptvc = NULL;
    proto_tree          *temp_tree = NULL;
    int                  length_remaining = 0;
    uint32_t             nds_flags;
    uint32_t             ping_version;

#ifdef FAKE_TREE_IS_VISIBLE
    if (ncp_tree) {
        PTREE_DATA(ncp_tree)->visible=1;
    }
#endif

    func = tvb_get_uint8(tvb, 6);
    subfunc = tvb_get_uint8(tvb, 7);

    ncp_rec = ncp_record_find(func, subfunc);

    /* Fill in the INFO column. */
    if (ncp_rec)
    {
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDS");

        col_set_str(pinfo->cinfo, COL_INFO, "C Ping for NDS");

    }
    if (!pinfo->fd->visited)
    {

        /* This is the first time we've looked at this packet.
           Keep track of the address and connection whence the request
           came, and the address and connection to which the request
           is being sent, so that we can match up calls with replies.
           (We don't include the sequence number, as we may want
           to have all packets over the same connection treated
           as being part of a single conversation so that we can
           let the user select that conversation to be displayed.) */

        conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                         CONVERSATION_NCP, nw_connection, nw_connection, 0);

        if (conversation == NULL)
        {
            /* It's not part of any conversation - create a new one. */
            conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
                                            CONVERSATION_NCP, nw_connection, nw_connection, 0);
        }

        request_value = ncp_hash_insert(conversation, sequence, ncp_rec, pinfo->num);
        request_value->req_frame_num = pinfo->num;
        request_value->req_frame_time=pinfo->abs_ts;

        /* If this is the first time we're examining the packet,
         * check to see if this NCP type uses a "request condition".
         * If so, we have to build a proto_tree because request conditions
         * use display filters to work, and without a proto_tree,
         * display filters can't possibly work. If we already have
         * a proto_tree, then wonderful. If we don't, we need to build
         * one. */
        if (ncp_rec && !ncp_tree) {
            proto_item *ti;

            temp_tree = proto_tree_create_root(pinfo);
            proto_tree_set_visible(temp_tree, false);
            ti = proto_tree_add_item(temp_tree, proto_ncp, tvb, 0, -1, ENC_NA);
            ncp_tree = proto_item_add_subtree(ti, ett_ncp);
        }
    }

    if (ncp_tree) {
        /* If the dissection throws an exception, be sure to free
         * the temporary proto_tree that was created. Because of the
         * way the CLEANUP_PUSH macro works, we can't put it in an 'if'
         * block; it has to be in the same scope as the terminating
         * CLEANUP_POP or CLEANUP_POP_AND_ALLOC. So, we always
         * call CLEANUP_POP and friends, but the value of temp_tree is
         * NULL if no cleanup is needed, and non-null if cleanup is needed.
         */
        CLEANUP_PUSH(free_proto_tree, temp_tree);

        switch (type) {

        case NCP_BROADCAST_SLOT:
            ; /* nothing */
            break;

        case NCP_SERVICE_REQUEST:
            proto_tree_add_uint_format_value(ncp_tree, hf_ncp_func, tvb, 6, 1,
                                       func, "%u (0x%02X), %s",
                                       func, func, ncp_rec ? ncp_rec->name : "Unknown");

            proto_tree_add_uint(ncp_tree, hf_ncp_subfunc, tvb, 7, 1, subfunc);

            length_remaining = tvb_reported_length_remaining(tvb, 8);

            if (length_remaining >= 8) {
                proto_item *pi;

                ping_version = tvb_get_letohl(tvb, 8);
                proto_tree_add_uint(ncp_tree, hf_nds_ping_version, tvb, 8,
                                    4, ping_version);
                nds_flags = tvb_get_letohl(tvb, 12);
                if (request_value){
                    request_value->nds_request_verb = 0xf0;
                    request_value->req_nds_flags = nds_flags;
                }

                pi = proto_tree_add_uint(ncp_tree, hf_ncp_nds_verb, tvb, 0, 0, 240);
                proto_item_set_hidden(pi);

                proto_tree_add_bitmask(ncp_tree, tvb, 12, hf_pingflags1, ett_ncp, ncp_pingflags1, ENC_LITTLE_ENDIAN);
                proto_tree_add_bitmask(ncp_tree, tvb, 14, hf_pingflags2, ett_ncp, ncp_pingflags2, ENC_LITTLE_ENDIAN);
            }
            break;

        default:
            ; /* nothing */
            break;
        }
        ptvc = ptvcursor_new(pinfo->pool, ncp_tree, tvb, 7);
        if (ncp_rec && ncp_rec->request_ptvc) {
            clear_repeat_vars();
            process_ptvc_record(ptvc, pinfo, ncp_rec->request_ptvc, NULL, true, ncp_rec, true);
        }
        ptvcursor_free(ptvc);

        /* Free the temporary proto_tree */
        CLEANUP_CALL_AND_POP;
    }
}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 *
 * vi: set shiftwidth=4 tabstop=4 expandtab filetype=c:
 * :indentSize=4:tabSize=4:noTabs=true:
 */
